diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs
index c2c600fae..11a41a9d6 100644
--- a/android/.settings/org.eclipse.buildship.core.prefs
+++ b/android/.settings/org.eclipse.buildship.core.prefs
@@ -1,11 +1,11 @@
-arguments=--init-script /var/folders/_m/gmgx0cmn6rzb80znp6s3hl800000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/_m/gmgx0cmn6rzb80znp6s3hl800000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
+arguments=--init-script /var/folders/tm/qsvqk80d0t30zlr71v0yf1m00000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/tm/qsvqk80d0t30zlr71v0yf1m00000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
-java.home=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
+java.home=/Users/peronif5/Library/Java/JavaVirtualMachines/openjdk-21.0.2/Contents/Home
jvm.arguments=
offline.mode=false
override.workspace.settings=true
diff --git a/android/app/.settings/org.eclipse.jdt.core.prefs b/android/app/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..626e0e1d5
--- /dev/null
+++ b/android/app/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
+org.eclipse.jdt.core.compiler.compliance=17
+org.eclipse.jdt.core.compiler.source=17
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index eb98c01af..62d7d130c 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -6,4 +6,4 @@
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning"/>
-
+
\ No newline at end of file
diff --git a/android/app/src/main/assets/fonts/Figtree-Italic-VariableFont_wght.ttf b/android/app/src/main/assets/fonts/Figtree-Italic-VariableFont_wght.ttf
new file mode 100644
index 000000000..fd997441d
Binary files /dev/null and b/android/app/src/main/assets/fonts/Figtree-Italic-VariableFont_wght.ttf differ
diff --git a/android/app/src/main/assets/fonts/Figtree-VariableFont_wght.ttf b/android/app/src/main/assets/fonts/Figtree-VariableFont_wght.ttf
new file mode 100644
index 000000000..06f9fe572
Binary files /dev/null and b/android/app/src/main/assets/fonts/Figtree-VariableFont_wght.ttf differ
diff --git a/android/link-assets-manifest.json b/android/link-assets-manifest.json
new file mode 100644
index 000000000..d1e688d7f
--- /dev/null
+++ b/android/link-assets-manifest.json
@@ -0,0 +1,13 @@
+{
+ "migIndex": 1,
+ "data": [
+ {
+ "path": "src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf",
+ "sha1": "8e76cbc3e74d415e8790eb62dfa1705539609dcb"
+ },
+ {
+ "path": "src/assets/fonts/Figtree-VariableFont_wght.ttf",
+ "sha1": "118c5e4678ec5f5f7222fb968cd88a5a92e7629d"
+ }
+ ]
+}
diff --git a/babel.config.js b/babel.config.js
index 0c546e12c..8029e1c0f 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -20,12 +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/app/services',
+ '@store': './src/store',
+ '@app': './src/app',
},
extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
root: ['./src'],
diff --git a/index.js b/index.js
index d36d631a1..0807a1438 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,4 @@
import './shim'
-import { ThemeProvider } from '@shopify/restyle'
import React from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { AppRegistry } from 'react-native'
@@ -9,15 +8,14 @@ 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 { darkThemeColors, theme } from './src/theme/theme'
import './src/utils/i18n'
// eslint-disable-next-line no-undef
@@ -35,33 +33,26 @@ function fallbackRender(props) {
const render = () => {
return (
- {
+ await persistor.purge()
}}
>
- {
- await persistor.purge()
- }}
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
)
}
diff --git a/ios/Gemfile.lock b/ios/Gemfile.lock
index 454a44902..aab86a0a8 100644
--- a/ios/Gemfile.lock
+++ b/ios/Gemfile.lock
@@ -5,25 +5,25 @@ GEM
base64
nkf
rexml
- addressable (2.8.6)
- public_suffix (>= 2.0.2, < 6.0)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
- aws-partitions (1.912.0)
- aws-sdk-core (3.191.6)
+ aws-partitions (1.986.0)
+ aws-sdk-core (3.209.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
- aws-sigv4 (~> 1.8)
+ aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.78.0)
- aws-sdk-core (~> 3, >= 3.191.0)
- aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.146.1)
- aws-sdk-core (~> 3, >= 3.191.0)
+ aws-sdk-kms (1.94.0)
+ aws-sdk-core (~> 3, >= 3.207.0)
+ aws-sigv4 (~> 1.5)
+ aws-sdk-s3 (1.167.0)
+ aws-sdk-core (~> 3, >= 3.207.0)
aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.8)
- aws-sigv4 (1.8.0)
+ aws-sigv4 (~> 1.5)
+ aws-sigv4 (1.10.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
@@ -38,8 +38,8 @@ GEM
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
- excon (0.110.0)
- faraday (1.10.3)
+ excon (0.112.0)
+ faraday (1.10.4)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -60,15 +60,15 @@ GEM
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
- faraday-net_http (1.0.1)
+ faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
- faraday_middleware (1.2.0)
+ faraday_middleware (1.2.1)
faraday (~> 1.0)
fastimage (2.3.1)
- fastlane (2.220.0)
+ fastlane (2.224.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -126,7 +126,7 @@ GEM
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.11.0, < 2.a)
- google-cloud-core (1.7.0)
+ google-cloud-core (1.7.1)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
@@ -147,31 +147,31 @@ GEM
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
- http-cookie (1.0.5)
+ http-cookie (1.0.7)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.2)
json (2.7.2)
- jwt (2.8.1)
+ jwt (2.9.3)
base64
- mini_magick (4.12.0)
+ mini_magick (4.13.2)
mini_mime (1.1.5)
multi_json (1.15.0)
- multipart-post (2.4.0)
+ multipart-post (2.4.1)
nanaimo (0.3.0)
naturally (2.2.1)
nkf (0.2.0)
- optparse (0.4.0)
+ optparse (0.5.0)
os (1.1.4)
plist (3.7.1)
- public_suffix (5.0.5)
+ public_suffix (6.0.1)
rake (13.2.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
- rexml (3.2.6)
+ rexml (3.3.8)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
@@ -193,15 +193,15 @@ GEM
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
- unicode-display_width (2.5.0)
+ unicode-display_width (2.6.0)
word_wrap (1.0.0)
- xcodeproj (1.24.0)
+ xcodeproj (1.25.1)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
- rexml (~> 3.2.4)
+ rexml (>= 3.3.6, < 4.0)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
@@ -215,4 +215,4 @@ DEPENDENCIES
fastlane
BUNDLED WITH
- 2.5.4
+ 2.5.18
diff --git a/ios/HeliumWallet.xcodeproj/project.pbxproj b/ios/HeliumWallet.xcodeproj/project.pbxproj
index 451d12700..1ca57faaf 100644
--- a/ios/HeliumWallet.xcodeproj/project.pbxproj
+++ b/ios/HeliumWallet.xcodeproj/project.pbxproj
@@ -8,18 +8,14 @@
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* HeliumWalletTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HeliumWalletTests.m */; };
+ 117516811AB44418A8ACF34F /* Figtree-VariableFont_wght.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C11FA61F64A54BB9B8AFA5F6 /* Figtree-VariableFont_wght.ttf */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.mm */; };
1A7DAB918483F1C2761BA7A4 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296757835722BB74360F9FEF /* ExpoModulesProvider.swift */; };
31B6D29CFC726A9C37946D71 /* libPods-HeliumWallet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B83B6ABAD63F1D810AF84CE5 /* libPods-HeliumWallet.a */; };
45330C4A223536223298B2A3 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645194928E31AE79BE70ED88 /* ExpoModulesProvider.swift */; };
- 50D1D6AC2763AAA2009D52C0 /* DMSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6A62763AAA2009D52C0 /* DMSans-Bold.ttf */; };
- 50D1D6AD2763AAA2009D52C0 /* DMSans-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6A72763AAA2009D52C0 /* DMSans-BoldItalic.ttf */; };
- 50D1D6AE2763AAA2009D52C0 /* DMSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6A82763AAA2009D52C0 /* DMSans-Medium.ttf */; };
- 50D1D6AF2763AAA2009D52C0 /* DMSans-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6A92763AAA2009D52C0 /* DMSans-MediumItalic.ttf */; };
- 50D1D6B02763AAA2009D52C0 /* DMSans-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6AA2763AAA2009D52C0 /* DMSans-Italic.ttf */; };
- 50D1D6B12763AAA2009D52C0 /* DMSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 50D1D6AB2763AAA2009D52C0 /* DMSans-Regular.ttf */; };
+ 7AA19242A2DE47E8AFC56882 /* Figtree-Italic-VariableFont_wght.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3440BC62530D461681D28DD7 /* Figtree-Italic-VariableFont_wght.ttf */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
9609D00027F4DE8D00CE3F93 /* RCTDateModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9609CFFF27F4DE8D00CE3F93 /* RCTDateModule.mm */; };
962862712BDCCAF70073839C /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
@@ -57,6 +53,10 @@
9DE3051C28510B8E00E46F9B /* HeliumWalletWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE3051B28510B8E00E46F9B /* HeliumWalletWidgetBundle.swift */; };
9DE3051E28510E3900E46F9B /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE3051D28510E3900E46F9B /* Utils.swift */; };
9DE305212851187D00E46F9B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9DE305232851187D00E46F9B /* Localizable.strings */; };
+ 9DEC730B2CAB265100DA649B /* Mapbox in Frameworks */ = {isa = PBXBuildFile; productRef = 5A94DB7A8D2811C850C94941 /* Mapbox */; };
+ 9DEC730C2CAB265100DA649B /* Mapbox in Frameworks */ = {isa = PBXBuildFile; productRef = CE0525B8C0183FCA3071F4F6 /* Mapbox */; };
+ 9DEC730D2CAB265100DA649B /* Mapbox in Frameworks */ = {isa = PBXBuildFile; productRef = 6B1147D96DED6C57572658F4 /* Mapbox */; };
+ 9DEC730E2CAB265100DA649B /* Mapbox in Frameworks */ = {isa = PBXBuildFile; productRef = 899688236472B5978CFDB459 /* Mapbox */; };
9DF6297C28D159FD002601C9 /* HeliumTickerAccessoryCornerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF6297B28D159FD002601C9 /* HeliumTickerAccessoryCornerView.swift */; };
9DF6297E28D1782D002601C9 /* HeliumTickerAccessoryRectangularView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF6297D28D1782D002601C9 /* HeliumTickerAccessoryRectangularView.swift */; };
9DF6298128D1787A002601C9 /* HeliumTickerAccessoryInlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DF6298028D1787A002601C9 /* HeliumTickerAccessoryInlineView.swift */; };
@@ -128,17 +128,12 @@
1EFDB5FA77191A99A2371AFB /* Pods-HeliumWallet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWallet.debug.xcconfig"; path = "Target Support Files/Pods-HeliumWallet/Pods-HeliumWallet.debug.xcconfig"; sourceTree = ""; };
1F0BFD5C668192F29DFDE754 /* Pods-OneSignalNotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.release.xcconfig"; sourceTree = ""; };
296757835722BB74360F9FEF /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-HeliumWallet-HeliumWalletTests/ExpoModulesProvider.swift"; sourceTree = ""; };
+ 3440BC62530D461681D28DD7 /* Figtree-Italic-VariableFont_wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Figtree-Italic-VariableFont_wght.ttf"; path = "../src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf"; sourceTree = ""; };
3B30E772B033A435C849D9CD /* Pods-HeliumWalletWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWalletWidgetExtension.release.xcconfig"; path = "Target Support Files/Pods-HeliumWalletWidgetExtension/Pods-HeliumWalletWidgetExtension.release.xcconfig"; sourceTree = ""; };
48E9A2B05D9F581F3DF9C71D /* libPods-HeliumWallet-HeliumWalletTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HeliumWallet-HeliumWalletTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
4C49B6B232EE708CBD605BA8 /* Pods-HeliumWallet-HeliumWalletTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWallet-HeliumWalletTests.debug.xcconfig"; path = "Target Support Files/Pods-HeliumWallet-HeliumWalletTests/Pods-HeliumWallet-HeliumWalletTests.debug.xcconfig"; sourceTree = ""; };
508E6F6B26FA22F400774B67 /* HeliumWallet-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HeliumWallet-Bridging-Header.h"; sourceTree = ""; };
50D1D6A42763AA88009D52C0 /* fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; name = fonts; path = ../src/assets/fonts; sourceTree = ""; };
- 50D1D6A62763AAA2009D52C0 /* DMSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-Bold.ttf"; path = "../src/assets/fonts/DMSans-Bold.ttf"; sourceTree = ""; };
- 50D1D6A72763AAA2009D52C0 /* DMSans-BoldItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-BoldItalic.ttf"; path = "../src/assets/fonts/DMSans-BoldItalic.ttf"; sourceTree = ""; };
- 50D1D6A82763AAA2009D52C0 /* DMSans-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-Medium.ttf"; path = "../src/assets/fonts/DMSans-Medium.ttf"; sourceTree = ""; };
- 50D1D6A92763AAA2009D52C0 /* DMSans-MediumItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-MediumItalic.ttf"; path = "../src/assets/fonts/DMSans-MediumItalic.ttf"; sourceTree = ""; };
- 50D1D6AA2763AAA2009D52C0 /* DMSans-Italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-Italic.ttf"; path = "../src/assets/fonts/DMSans-Italic.ttf"; sourceTree = ""; };
- 50D1D6AB2763AAA2009D52C0 /* DMSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "DMSans-Regular.ttf"; path = "../src/assets/fonts/DMSans-Regular.ttf"; sourceTree = ""; };
57910DBDCCCCDF8BFA3C6D9E /* Pods-OneSignalNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.debug.xcconfig"; sourceTree = ""; };
596BDD75E9EC4091C6156C0E /* libPods-HeliumWalletWidgetExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HeliumWalletWidgetExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; };
645194928E31AE79BE70ED88 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-HeliumWallet/ExpoModulesProvider.swift"; sourceTree = ""; };
@@ -150,7 +145,7 @@
96E4147227BEE4C300CE6EC1 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; };
96E4147427BEE4C300CE6EC1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
96E4147C27BEE61400CE6EC1 /* OneSignalNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneSignalNotificationServiceExtension.entitlements; sourceTree = ""; };
- 99ED3018E9DBF6106B1DE1A7 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = HeliumWallet/PrivacyInfo.xcprivacy; sourceTree = ""; };
+ 99ED3018E9DBF6106B1DE1A7 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = HeliumWallet/PrivacyInfo.xcprivacy; sourceTree = ""; };
9D05C88428527DF0008198FC /* HeliumWalletWidgetProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeliumWalletWidgetProvider.swift; sourceTree = ""; };
9D05C88628527E1E008198FC /* HeliumWalletWidgetSmallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeliumWalletWidgetSmallView.swift; sourceTree = ""; };
9D05C88828527E40008198FC /* HeliumWalletWidgetMediumView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeliumWalletWidgetMediumView.swift; sourceTree = ""; };
@@ -187,6 +182,7 @@
9DF6298028D1787A002601C9 /* HeliumTickerAccessoryInlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeliumTickerAccessoryInlineView.swift; sourceTree = ""; };
A887C33D5275223BA0B76656 /* Pods-HeliumWalletWidgetExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWalletWidgetExtension.debug.xcconfig"; path = "Target Support Files/Pods-HeliumWalletWidgetExtension/Pods-HeliumWalletWidgetExtension.debug.xcconfig"; sourceTree = ""; };
B83B6ABAD63F1D810AF84CE5 /* libPods-HeliumWallet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HeliumWallet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ C11FA61F64A54BB9B8AFA5F6 /* Figtree-VariableFont_wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Figtree-VariableFont_wght.ttf"; path = "../src/assets/fonts/Figtree-VariableFont_wght.ttf"; sourceTree = ""; };
DABD45A4821A707AEDF47E54 /* Pods-HeliumWallet-HeliumWalletTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWallet-HeliumWalletTests.release.xcconfig"; path = "Target Support Files/Pods-HeliumWallet-HeliumWalletTests/Pods-HeliumWallet-HeliumWalletTests.release.xcconfig"; sourceTree = ""; };
EA3C262A651DB9218F30F0E1 /* Pods-HeliumWallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HeliumWallet.release.xcconfig"; path = "Target Support Files/Pods-HeliumWallet/Pods-HeliumWallet.release.xcconfig"; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
@@ -198,6 +194,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9DEC730E2CAB265100DA649B /* Mapbox in Frameworks */,
962862742BDCCAF70073839C /* BuildFile in Frameworks */,
B3469F859005A4F164D08293 /* libPods-HeliumWallet-HeliumWalletTests.a in Frameworks */,
);
@@ -207,6 +204,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9DEC730B2CAB265100DA649B /* Mapbox in Frameworks */,
962862712BDCCAF70073839C /* BuildFile in Frameworks */,
31B6D29CFC726A9C37946D71 /* libPods-HeliumWallet.a in Frameworks */,
);
@@ -216,6 +214,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9DEC730C2CAB265100DA649B /* Mapbox in Frameworks */,
962862722BDCCAF70073839C /* BuildFile in Frameworks */,
C4EB4BD0A9AAABC0002181CC /* libPods-OneSignalNotificationServiceExtension.a in Frameworks */,
);
@@ -225,6 +224,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9DEC730D2CAB265100DA649B /* Mapbox in Frameworks */,
962862732BDCCAF70073839C /* BuildFile in Frameworks */,
9D7DB3B02850EC14004D9409 /* SwiftUI.framework in Frameworks */,
9D7DB3AF2850EC14004D9409 /* WidgetKit.framework in Frameworks */,
@@ -281,6 +281,15 @@
name = ExpoModulesProviders;
sourceTree = "";
};
+ 1DE256FAD99A492B952D4632 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 3440BC62530D461681D28DD7 /* Figtree-Italic-VariableFont_wght.ttf */,
+ C11FA61F64A54BB9B8AFA5F6 /* Figtree-VariableFont_wght.ttf */,
+ );
+ name = Resources;
+ sourceTree = "";
+ };
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -313,12 +322,6 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
- 50D1D6A62763AAA2009D52C0 /* DMSans-Bold.ttf */,
- 50D1D6A72763AAA2009D52C0 /* DMSans-BoldItalic.ttf */,
- 50D1D6AA2763AAA2009D52C0 /* DMSans-Italic.ttf */,
- 50D1D6A82763AAA2009D52C0 /* DMSans-Medium.ttf */,
- 50D1D6A92763AAA2009D52C0 /* DMSans-MediumItalic.ttf */,
- 50D1D6AB2763AAA2009D52C0 /* DMSans-Regular.ttf */,
50D1D6A42763AA88009D52C0 /* fonts */,
13B07FAE1A68108700A75B9A /* HeliumWallet */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
@@ -329,6 +332,7 @@
2D16E6871FA4F8E400B85C8A /* Frameworks */,
E233CBF5F47BEE60B243DCF8 /* Pods */,
1DC951AB9D06BB3015E8CAE6 /* ExpoModulesProviders */,
+ 1DE256FAD99A492B952D4632 /* Resources */,
);
indentWidth = 2;
sourceTree = "";
@@ -627,15 +631,11 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 50D1D6AC2763AAA2009D52C0 /* DMSans-Bold.ttf in Resources */,
- 50D1D6AD2763AAA2009D52C0 /* DMSans-BoldItalic.ttf in Resources */,
- 50D1D6AE2763AAA2009D52C0 /* DMSans-Medium.ttf in Resources */,
- 50D1D6AF2763AAA2009D52C0 /* DMSans-MediumItalic.ttf in Resources */,
- 50D1D6B02763AAA2009D52C0 /* DMSans-Italic.ttf in Resources */,
- 50D1D6B12763AAA2009D52C0 /* DMSans-Regular.ttf in Resources */,
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
AB02F1297F7F91A0FD2532BD /* PrivacyInfo.xcprivacy in Resources */,
+ 7AA19242A2DE47E8AFC56882 /* Figtree-Italic-VariableFont_wght.ttf in Resources */,
+ 117516811AB44418A8ACF34F /* Figtree-VariableFont_wght.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1079,7 +1079,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1117,7 +1117,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1303,7 +1303,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
@@ -1348,7 +1348,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.helium.wallet.app.OneSignalNotificationServiceExtension;
@@ -1396,7 +1396,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
@@ -1445,7 +1445,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 2.10.0;
+ MARKETING_VERSION = 3.0.0;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.helium.wallet.app.HeliumWalletWidget;
diff --git a/ios/HeliumWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/HeliumWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 8c8230ba7..7ebcc34da 100644
--- a/ios/HeliumWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/ios/HeliumWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,5 +1,4 @@
{
- "originHash" : "e70d3525c8e2819a8b34f22909815dab5c700c25a06c32388f3930f7b3627768",
"pins" : [
{
"identity" : "maplibre-gl-native-distribution",
@@ -9,7 +8,25 @@
"revision" : "ffda61e298c1490d4860d5184e80d618aaadc089",
"version" : "5.13.0"
}
+ },
+ {
+ "identity" : "swiftui-charts",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/spacenation/swiftui-charts",
+ "state" : {
+ "revision" : "b044e7eb04d0026490eecb115f4fc07197dad942",
+ "version" : "1.1.0"
+ }
+ },
+ {
+ "identity" : "swiftui-shapes",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/spacenation/swiftui-shapes.git",
+ "state" : {
+ "revision" : "c58b15c37eae9bd20525c6daa93a06a689ca75cb",
+ "version" : "1.1.0"
+ }
}
],
- "version" : 3
+ "version" : 2
}
diff --git a/ios/HeliumWallet/Info.plist b/ios/HeliumWallet/Info.plist
index 70ace53b9..99d6bd42d 100644
--- a/ios/HeliumWallet/Info.plist
+++ b/ios/HeliumWallet/Info.plist
@@ -44,12 +44,11 @@
LSRequiresIPhoneOS
NSAppTransportSecurity
-
-
+
NSAllowsArbitraryLoads
NSAllowsLocalNetworking
-
+
NSExceptionDomains
ec2-35-82-2-45.us-west-2.compute.amazonaws.com
@@ -79,12 +78,8 @@
UIAppFonts
- DMSans-Bold.ttf
- DMSans-BoldItalic.ttf
- DMSans-Italic.ttf
- DMSans-Medium.ttf
- DMSans-MediumItalic.ttf
- DMSans-Regular.ttf
+ Figtree-Italic-VariableFont_wght.ttf
+ Figtree-VariableFont_wght.ttf
UIBackgroundModes
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 3a1791f8c..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
@@ -1885,16 +1945,18 @@ SPEC CHECKSUMS:
ExpoSecureStore: 060cebcb956b80ddae09821610ac1aa9e1ac74cd
EXSplashScreen: fbf0ec78e9cee911df188bf17b4fe51d15a84b87
FBLazyVector: ac12dc084d1c8ec4cc4d7b3cf1b0ebda6dab85af
- fmt: 8083860262b879fc92bca720969c91bdb88ada93
- glog: 77f46f3d5c779b34a09b51a92fa9e0fcab64df1c
+ fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
+ glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f
helium-react-native-sdk: 54928dcd95ea131437ac6e269cf5bb2d473bf57f
- hermes-engine: e52d9706e7fd6078e529d8ada1af7b95946c4ce6
+ 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: 36944e180e3143948e1c8b0c5eade65a3dd45142
+ RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
RCTDeprecation: 3afceddffa65aee666dafd6f0116f1d975db1584
RCTRequired: ec1239bc9d8bf63e10fb92bd8b26171a9258e0c1
RCTTypeSafety: f5ecbc86c5c5fa163c05acb7a1c5012e15b5f994
@@ -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
- Yoga: 2246eea72aaf1b816a68a35e6e4b74563653ae09
+ 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/ios/link-assets-manifest.json b/ios/link-assets-manifest.json
new file mode 100644
index 000000000..d1e688d7f
--- /dev/null
+++ b/ios/link-assets-manifest.json
@@ -0,0 +1,13 @@
+{
+ "migIndex": 1,
+ "data": [
+ {
+ "path": "src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf",
+ "sha1": "8e76cbc3e74d415e8790eb62dfa1705539609dcb"
+ },
+ {
+ "path": "src/assets/fonts/Figtree-VariableFont_wght.ttf",
+ "sha1": "118c5e4678ec5f5f7222fb968cd88a5a92e7629d"
+ }
+ ]
+}
diff --git a/package.json b/package.json
index 56c68acb9..5089cd4ec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "helium-wallet",
- "version": "2.10.0",
+ "version": "3.0.0",
"private": true,
"scripts": {
"postinstall": "patch-package && ./node_modules/.bin/rn-nodeify --hack --install && npx jetify",
@@ -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,36 +31,40 @@
"@babel/preset-typescript": "7.21.0",
"@bonfida/spl-name-service": "^1.1.1",
"@coral-xyz/anchor": "^0.28.0",
- "@gorhom/bottom-sheet": "4.6.0",
+ "@gorhom/bottom-sheet": "5.0.4",
"@gorhom/portal": "1.0.14",
- "@helium/account-fetch-cache": "0.9.7",
- "@helium/account-fetch-cache-hooks": "0.9.7",
+ "@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.14",
+ "@helium/account-fetch-cache-hooks": "0.9.14",
"@helium/address": "4.10.2",
- "@helium/circuit-breaker-sdk": "^0.9.7",
+ "@helium/circuit-breaker-sdk": "^0.9.14",
"@helium/crypto-react-native": "4.8.0",
- "@helium/currency-utils": "^0.9.7",
- "@helium/data-credits-sdk": "^0.9.7",
- "@helium/distributor-oracle": "0.9.7",
- "@helium/fanout-sdk": "^0.9.7",
- "@helium/helium-entity-manager-sdk": "^0.9.7",
- "@helium/helium-react-hooks": "0.9.7",
- "@helium/helium-sub-daos-sdk": "^0.9.7",
+ "@helium/currency-utils": "^0.9.14",
+ "@helium/data-credits-sdk": "^0.9.14",
+ "@helium/distributor-oracle": "0.9.14",
+ "@helium/fanout-sdk": "^0.9.14",
+ "@helium/helium-entity-manager-sdk": "^0.9.14",
+ "@helium/helium-react-hooks": "0.9.14",
+ "@helium/helium-sub-daos-sdk": "^0.9.14",
"@helium/http": "4.7.5",
- "@helium/idls": "0.9.7",
- "@helium/lazy-distributor-sdk": "^0.9.7",
+ "@helium/idls": "0.9.14",
+ "@helium/lazy-distributor-sdk": "^0.9.14",
"@helium/modular-governance-hooks": "^0.0.13",
"@helium/modular-governance-idls": "0.0.13",
"@helium/onboarding": "4.11.0",
"@helium/organization-sdk": "^0.0.13",
"@helium/proto-ble": "4.0.0",
"@helium/react-native-sdk": "3.0.5",
- "@helium/spl-utils": "0.9.7",
+ "@helium/spl-utils": "0.9.14",
"@helium/state-controller-sdk": "^0.0.13",
- "@helium/sus": "0.9.7",
+ "@helium/sus": "0.9.14",
"@helium/transactions": "4.8.1",
- "@helium/treasury-management-sdk": "^0.9.7",
- "@helium/voter-stake-registry-hooks": "0.9.7",
- "@helium/voter-stake-registry-sdk": "0.9.7",
+ "@helium/treasury-management-sdk": "^0.9.14",
+ "@helium/voter-stake-registry-hooks": "0.9.14",
+ "@helium/voter-stake-registry-sdk": "0.9.14",
"@helium/wallet-link": "4.11.0",
"@jup-ag/api": "^6.0.6",
"@keystonehq/keystone-sdk": "^0.8.0",
@@ -66,10 +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.26",
"@onsol/tldparser": "^0.5.3",
"@react-native-async-storage/async-storage": "1.18.1",
"@react-native-community/blur": "4.3.0",
@@ -78,13 +85,15 @@
"@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",
- "@shopify/restyle": "1.8.0",
+ "@rnmapbox/maps": "^10.1.31",
+ "@shopify/restyle": "2.4.2",
"@solana/spl-account-compression": "0.1.4",
"@solana/spl-memo": "0.2.3",
"@solana/spl-token": "0.3.6",
@@ -132,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",
@@ -156,13 +167,17 @@
"react-error-boundary": "^4.0.13",
"react-i18next": "11.18.4",
"react-native": "0.74.5",
+ "react-native-animated-numbers": "^0.6.2",
"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",
@@ -173,13 +188,13 @@
"react-native-localize": "2.2.3",
"react-native-mail": "6.1.1",
"react-native-markdown-display": "^7.0.0-alpha.2",
- "react-native-navigation-bar-color": "2.0.2",
+ "react-native-navigation-bar-color": "^2.0.2",
"react-native-network-info": "5.2.1",
"react-native-onesignal": "5.2.2",
"react-native-os": "^1.2.6",
"react-native-pager-view": "6.1.2",
"react-native-permissions": "^3.9.0",
- "react-native-qrcode-svg": "6.1.2",
+ "react-native-qrcode-svg": "^6.3.2",
"react-native-randombytes": "3.6.1",
"react-native-reanimated": "3.14.0",
"react-native-safe-area-context": "4.10.8",
@@ -187,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",
@@ -197,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",
@@ -276,11 +293,11 @@
"@types/react": "18",
"react": "18.2.0",
"@solana/wallet-adapter-react": "0.15.33",
- "@helium/account-fetch-cache": "^0.9.7",
- "@helium/account-fetch-cache-hooks": "^0.9.7",
- "@helium/helium-react-hooks": "^0.9.7",
- "@helium/voter-stake-registry-hooks": "^0.9.7",
- "@helium/voter-stake-registry-sdk": "^0.9.7",
+ "@helium/account-fetch-cache": "^0.9.14",
+ "@helium/account-fetch-cache-hooks": "^0.9.14",
+ "@helium/helium-react-hooks": "^0.9.14",
+ "@helium/voter-stake-registry-hooks": "^0.9.14",
+ "@helium/voter-stake-registry-sdk": "^0.9.14",
"@helium/modular-governance-hooks": "^0.0.13",
"@helium/onboarding": "4.11.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 @@
-+
-+RCTMGL
-\ 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 71%
rename from src/App.tsx
rename to src/app/App.tsx
index 0eaba2306..5e3bd0983 100644
--- a/src/App.tsx
+++ b/src/app/App.tsx
@@ -2,43 +2,41 @@ 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 { darkThemeColors, lightThemeColors, theme } from '@theme/theme'
-import { useColorScheme } from '@theme/themeHooks'
+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 { LogBox } from 'react-native'
+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'
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 NetworkAwareStatusBar from './components/NetworkAwareStatusBar'
-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 */
@@ -48,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',
@@ -64,38 +63,41 @@ const App = () => {
'ws error: received bad response code from server 429',
'Ignored unsubscribe request because an active subscription with id',
'accountFetchCache Batching account fetch of',
+ 'VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality - use another VirtualizedList-backed container instead.',
])
const { appState } = useAppState()
const { restored: accountsRestored } = useAccountStorage()
- // const { cache } = useSolana()
const { setOpenedNotification } = useNotificationStorage()
const linking = useDeepLinking()
- const colorScheme = useColorScheme()
+ const themeObject = useMemo(() => {
+ return darkTheme
+ }, [])
+
+ if (Platform.OS === 'android') {
+ if (UIManager.setLayoutAnimationEnabledExperimental) {
+ UIManager.setLayoutAnimationEnabledExperimental(true)
+ }
+ }
const colorAdaptedTheme = useMemo(
() => ({
- ...theme,
- colors: colorScheme === 'light' ? lightThemeColors : darkThemeColors,
+ ...themeObject,
}),
- [colorScheme],
+ [themeObject],
)
const navTheme = useMemo(
() => ({
...DarkTheme,
- dark: colorScheme === 'light',
+ dark: true,
colors: {
...DarkTheme.colors,
- background:
- colorScheme === 'light'
- ? lightThemeColors.primaryBackground
- : darkThemeColors.primaryBackground,
+ background: themeObject.colors.primaryBackground,
},
}),
-
- [colorScheme],
+ [themeObject],
)
useMount(() => {
@@ -114,6 +116,10 @@ const App = () => {
return (
+
@@ -142,7 +148,6 @@ const App = () => {
-
{/* place app specific modals here */}
diff --git a/src/navigation/NavigationHelper.ts b/src/app/NavigationHelper.ts
similarity index 70%
rename from src/navigation/NavigationHelper.ts
rename to src/app/NavigationHelper.ts
index fc6120b1b..e887d1886 100644
--- a/src/navigation/NavigationHelper.ts
+++ b/src/app/NavigationHelper.ts
@@ -1,11 +1,11 @@
import { createNavigationContainerRef } from '@react-navigation/native'
-import { HomeStackParamList } from '../features/home/homeTypes'
+import { AccountsServiceStackParamList } from 'src/app/services/AccountsService'
import { RootStackParamList } from './rootTypes'
export const navigationRef = createNavigationContainerRef()
export const navToImportAccount = (
- params: HomeStackParamList['ReImportAccountNavigator'],
+ params: AccountsServiceStackParamList['ReImportAccountNavigator'],
) => {
if (!navigationRef.isReady()) return
navigationRef.navigate('ReImportAccountNavigator' as any, params as any)
diff --git a/src/app/RootNavigator.tsx b/src/app/RootNavigator.tsx
new file mode 100644
index 000000000..1535cdc85
--- /dev/null
+++ b/src/app/RootNavigator.tsx
@@ -0,0 +1,96 @@
+import {
+ StackNavigationOptions,
+ createStackNavigator,
+} from '@react-navigation/stack'
+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 '@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
+
+const RootNavigator = () => {
+ const { currentAccount } = useAccountStorage()
+ const colors = useColors()
+ const RootStack = createStackNavigator()
+
+ useEffect(() => {
+ if (currentAccount) {
+ changeNavigationBarColor(colors.primaryText, true, false)
+ } else {
+ changeNavigationBarColor(colors.primaryBackground, true, false)
+ }
+ }, [colors, currentAccount])
+
+ const initialRouteName = useMemo(() => {
+ return currentAccount ? 'ServiceSheetNavigator' : 'OnboardingNavigator'
+ }, [currentAccount])
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default memo(RootNavigator)
diff --git a/src/navigation/rootTypes.ts b/src/app/rootTypes.ts
similarity index 90%
rename from src/navigation/rootTypes.ts
rename to src/app/rootTypes.ts
index 79ddc408e..95b145444 100644
--- a/src/navigation/rootTypes.ts
+++ b/src/app/rootTypes.ts
@@ -1,11 +1,11 @@
import { LinkWalletRequest, SignHotspotRequest } from '@helium/wallet-link'
import { StackNavigationProp } from '@react-navigation/stack'
import { KeystoneAccountType } from 'src/features/keystone/SelectKeystoneAccountsScreen'
-import { PaymentRouteParam } from '../features/home/homeTypes'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
export type RootStackParamList = {
OnboardingNavigator: undefined
- TabBarNavigator: undefined
+ ServiceSheetNavigator: undefined
LinkWallet: LinkWalletRequest
SignHotspot: SignHotspotRequest & { submit?: boolean }
PaymentScreen: undefined | PaymentRouteParam
diff --git a/src/app/services/AccountsService/accountServiceTypes.ts b/src/app/services/AccountsService/accountServiceTypes.ts
new file mode 100644
index 000000000..0bb837239
--- /dev/null
+++ b/src/app/services/AccountsService/accountServiceTypes.ts
@@ -0,0 +1,9 @@
+import { StackNavigationProp } from '@react-navigation/stack'
+
+export type AccountsServiceStackParamList = {
+ YourWalletsPage: undefined
+ AddNewAccountNavigator: undefined
+}
+
+export type AccountsServiceNavigationProp =
+ StackNavigationProp
diff --git a/src/app/services/AccountsService/index.tsx b/src/app/services/AccountsService/index.tsx
new file mode 100644
index 000000000..b2aea7e1d
--- /dev/null
+++ b/src/app/services/AccountsService/index.tsx
@@ -0,0 +1,78 @@
+import React, { useMemo } from 'react'
+import {
+ StackNavigationOptions,
+ StackNavigationProp,
+ createStackNavigator,
+} from '@react-navigation/stack'
+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'
+import ImportAccountNavigator from '@features/onboarding/import/ImportAccountNavigator'
+import KeystoneNavigator from '@features/keystone/KeystoneNavigator'
+import YourWalletsPage from './pages/YourWalletsPage'
+
+export type AccountsServiceStackParamList = {
+ YourWalletsPage: undefined
+ AddNewAccountNavigator: undefined
+ AccountAssignScreen: undefined | RouteAccount
+ ReImportAccountNavigator:
+ | undefined
+ | {
+ screen: 'AccountImportScreen'
+ params: {
+ restoringAccount?: boolean
+ accountAddress?: string
+ }
+ }
+ KeystoneNavigator: {
+ screen: 'KeystoneNavigator'
+ params: {
+ screen: string
+ }
+ }
+}
+
+export type AccountsServiceNavigationProp =
+ StackNavigationProp
+
+const AccountsServiceStack =
+ createStackNavigator()
+
+const AccountsService = () => {
+ const colors = useColors()
+ const screenOptions: StackNavigationOptions = useMemo(
+ () => ({
+ headerShown: false,
+ animationEnabled: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ }),
+ [colors],
+ )
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export default AccountsService
diff --git a/src/app/services/AccountsService/pages/YourWalletsPage.tsx b/src/app/services/AccountsService/pages/YourWalletsPage.tsx
new file mode 100644
index 000000000..395af534b
--- /dev/null
+++ b/src/app/services/AccountsService/pages/YourWalletsPage.tsx
@@ -0,0 +1,419 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import Text from '@components/Text'
+import { useTranslation } from 'react-i18next'
+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 '@config/storage/AccountStorageProvider'
+import { NetTypes } from '@helium/address'
+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 '@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 '@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 'src/app/services/serviceSheetTypes'
+import CircleLoader from '@components/CircleLoader'
+import ScrollBox from '@components/ScrollBox'
+import { AccountsServiceNavigationProp } from '../accountServiceTypes'
+
+const YourWalletsPage = () => {
+ const { t } = useTranslation()
+ const [addingSubAccount, setAddingSubAccount] = useState(false)
+ const [switchingAccounts, setSwitchingAccounts] = useState<
+ CSAccount | undefined
+ >()
+ const spacing = useSpacing()
+ const { setOnboardingData, onboardingData } = useOnboarding()
+ const colors = useColors()
+ const navigation = useNavigation<
+ AccountsServiceNavigationProp & ServiceSheetNavigationProp
+ >()
+ const { sortedAccounts, currentAccount, setCurrentAccount, accounts } =
+ useAccountStorage()
+ const { bottom } = useSafeAreaInsets()
+ const [footerHeight, setFooterHeight] = useLayoutHeight()
+
+ const handleAddSub = useCallback(
+ async (acc: CSAccount) => {
+ setAddingSubAccount(true)
+ try {
+ if (!currentAccount) {
+ throw new Error('No current account')
+ }
+ const storage = await getSecureAccount(currentAccount.address)
+ const seed = bip39.mnemonicToSeedSync(
+ storage?.mnemonic?.join(' ') || '',
+ '',
+ )
+
+ if (!seed || !acc?.derivationPath) {
+ throw new Error('Missing seed or derivation path')
+ }
+ const currentPath = acc.derivationPath
+ const takenAddresses = new Set(
+ Object.values(accounts || {}).map((a) => a.solanaAddress),
+ )
+ let currentAccountNum =
+ currentPath === HELIUM_DERIVATION
+ ? 0
+ : Number(currentPath.split('/')[3].replace("'", '')) + 1
+ let derivationPath = solanaDerivation(currentAccountNum, 0)
+ let keypair = await keypairFromSeed(seed, derivationPath)
+ while (
+ currentAccountNum < 100 &&
+ (!keypair || takenAddresses.has(keypair.publicKey.toBase58()))
+ ) {
+ currentAccountNum += 1
+ derivationPath = solanaDerivation(currentAccountNum, 0)
+ keypair = await keypairFromSeed(seed, derivationPath)
+ }
+ if (currentAccountNum >= 100) {
+ throw new Error('More than 100 accounts are not supported')
+ }
+ if (keypair) {
+ const words = (await getSecureAccount(acc.address))?.mnemonic
+ setOnboardingData({
+ ...onboardingData,
+ words,
+ paths: [
+ {
+ derivationPath,
+ keypair,
+ },
+ ],
+ })
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ navigation.navigate('AccountAssignScreen', {
+ words,
+ })
+ }
+
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ } catch (e: any) {
+ Toast.show(e.message || e.toString())
+ } finally {
+ setAddingSubAccount(false)
+ }
+ },
+ [accounts, currentAccount, navigation, onboardingData, setOnboardingData],
+ )
+
+ const filteredAccounts = useMemo(() => {
+ const grouped = sortedAccounts
+ .filter((a) => a.netType !== NetTypes.TESTNET)
+ .reduce((acc, account) => {
+ acc[account.mnemonicHash || 'none'] = [
+ ...(acc[account.mnemonicHash || 'none'] || []),
+ account,
+ ]
+ return acc
+ }, {} as { [key: string]: CSAccount[] })
+
+ const { none, ...rest } = grouped
+ const ret = Object.values(rest).map((accs, index) => ({
+ title: `Seed Phrase ${index + 1}`,
+ data: accs,
+ }))
+ if (none) {
+ ret.push({
+ title: 'Private Keys',
+ data: none,
+ })
+ }
+
+ return ret
+ }, [sortedAccounts])
+
+ const Header = useCallback(() => {
+ return (
+
+
+
+ {t('accountsService.title')}
+
+
+ )
+ }, [t])
+
+ const keyExtractor = useCallback((item) => item.address, [])
+
+ const handleAccountChange = useCallback(
+ (item: CSAccount) => () => {
+ setSwitchingAccounts(item)
+ },
+ [setSwitchingAccounts],
+ )
+
+ useEffect(() => {
+ if (!switchingAccounts) return
+
+ // Need to wait for a UI tick to allow the animation to finish
+ setTimeout(() => {
+ setCurrentAccount(switchingAccounts)
+ navigation.replace('WalletService')
+ }, 0)
+ }, [switchingAccounts, setCurrentAccount, navigation])
+
+ const renderItem = useCallback(
+ ({
+ item,
+ index,
+ section,
+ }: {
+ // eslint-disable-next-line react/no-unused-prop-types
+ index: number
+ // eslint-disable-next-line react/no-unused-prop-types
+ item: CSAccount
+ // eslint-disable-next-line react/no-unused-prop-types
+ section: {
+ title: string
+ data: CSAccount[]
+ }
+ }) => {
+ const { data } = section
+
+ const isSelected = item.address === currentAccount?.address
+ const showBottomBorder =
+ (data[index] &&
+ data[index].mnemonicHash !== currentAccount?.mnemonicHash) ||
+ section.title === 'Private Keys'
+ const isLast = index === data.length - 1
+ const accountAddress = item?.solanaAddress
+ const borderTopStartRadius = index === 0 ? '2xl' : undefined
+ const borderTopEndRadius = index === 0 ? '2xl' : undefined
+ const borderBottomStartRadius =
+ index === data.length - 1 && showBottomBorder ? '2xl' : undefined
+ const borderBottomEndRadius =
+ index === data.length - 1 && showBottomBorder ? '2xl' : undefined
+
+ return (
+
+
+
+
+ {item.alias}
+
+
+ {ellipsizeAddress(accountAddress || '', {
+ numChars: 4,
+ })}
+
+
+ {isSelected && (
+
+ )}
+
+ )
+ },
+ [currentAccount, handleAccountChange, colors],
+ )
+
+ const handleNetTypeChange = useCallback(
+ (nextNetType?: NetTypes.NetType) => {
+ setOnboardingData((prev) => {
+ let netType = nextNetType
+ if (netType === undefined) {
+ netType =
+ prev.netType === NetTypes.MAINNET
+ ? NetTypes.TESTNET
+ : NetTypes.MAINNET
+ }
+ return { ...prev, netType }
+ })
+ },
+ [setOnboardingData],
+ )
+
+ const handleAddNew = useCallback(() => {
+ handleNetTypeChange(NetTypes.MAINNET)
+ navigation.navigate('AddNewAccountNavigator')
+ }, [handleNetTypeChange, navigation])
+
+ const renderSectionHeader = useCallback(
+ ({ section: { title, data } }) => {
+ const firstSection = filteredAccounts[0].title === title
+
+ return (
+
+
+ {title}
+
+
+ )
+ },
+ [filteredAccounts, currentAccount],
+ )
+
+ const renderSectionFooter = useCallback(
+ ({ section: { data } }) => {
+ return (
+
+ )
+ },
+ [handleAddSub, currentAccount?.mnemonicHash],
+ )
+
+ const Footer = useCallback(() => {
+ return (
+
+ {/** TODO: Bring back when stickers page is added */}
+ {/*
+
+ */}
+
+
+
+
+
+ )
+ }, [bottom, handleAddNew, setFooterHeight])
+
+ if (switchingAccounts || addingSubAccount) {
+ return (
+
+
+ {addingSubAccount
+ ? t('accountsService.addingSubAccount')
+ : t('accountsService.switchingAccounts')}
+
+
+ {t('accountsService.pleaseBePatient')}
+
+
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+const SectionFooter: React.FC<{
+ data: CSAccount[]
+ isSelected: boolean
+ onAddSub: (acc: CSAccount) => void
+}> = ({ data, onAddSub, isSelected }) => {
+ const handleAddSub = useCallback(() => {
+ if (data[0] && data[0].mnemonicHash) {
+ onAddSub(data[data.length - 1])
+ }
+ }, [data, onAddSub])
+ const { t } = useTranslation()
+ return (
+
+ {isSelected && data[0] && data[0].mnemonicHash ? (
+
+
+ {t('connectedWallets.addSub')}
+
+
+
+ ) : null}
+
+ )
+}
+
+export default YourWalletsPage
diff --git a/src/app/services/BrowserService/index.tsx b/src/app/services/BrowserService/index.tsx
new file mode 100644
index 000000000..a24f36d1a
--- /dev/null
+++ b/src/app/services/BrowserService/index.tsx
@@ -0,0 +1,8 @@
+import BrowserNavigator from '@features/browser/BrowserNavigator'
+import React from 'react'
+
+const BrowserService = () => {
+ return
+}
+
+export default BrowserService
diff --git a/src/app/services/GovernanceService/index.tsx b/src/app/services/GovernanceService/index.tsx
new file mode 100644
index 000000000..3098cf863
--- /dev/null
+++ b/src/app/services/GovernanceService/index.tsx
@@ -0,0 +1,8 @@
+import GovernanceNavigator from '@features/governance/GovernanceNavigator'
+import React from 'react'
+
+const GovernanceService = () => {
+ return
+}
+
+export default GovernanceService
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/app/services/NotificationsService/index.tsx b/src/app/services/NotificationsService/index.tsx
new file mode 100644
index 000000000..4961b70f0
--- /dev/null
+++ b/src/app/services/NotificationsService/index.tsx
@@ -0,0 +1,8 @@
+import React from 'react'
+import NotificationsNavigator from '@features/notifications/NotificationsNavigator'
+
+const NotificationsService = () => {
+ return
+}
+
+export default NotificationsService
diff --git a/src/app/services/ServiceSheet.tsx b/src/app/services/ServiceSheet.tsx
new file mode 100644
index 000000000..6267d42ed
--- /dev/null
+++ b/src/app/services/ServiceSheet.tsx
@@ -0,0 +1,282 @@
+import React, { useCallback, useMemo, useRef, useState } from 'react'
+import Box from '@components/Box'
+import BottomSheet from '@gorhom/bottom-sheet'
+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'
+import SideDrawer from '@components/SideDrawer'
+import MenuButton from '@components/MenuButton'
+import { useNavigation } from '@react-navigation/native'
+import { ThemeProvider } from '@shopify/restyle'
+import { lightTheme } from '@config/theme/theme'
+import HeliumBottomSheet from '@components/HeliumBottomSheet'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+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,
+ 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) => {
+ setIsExpanded(false)
+ bottomSheetRef.current?.expand()
+
+ switch (value) {
+ default:
+ case 'wallet':
+ serviceNav.replace('WalletService')
+ break
+ case 'hotspots':
+ serviceNav.replace('HotspotService')
+ break
+ case 'governance':
+ serviceNav.replace('GovernanceService')
+ break
+ case 'browser':
+ serviceNav.replace('BrowserService')
+ break
+ case 'notifications':
+ serviceNav.replace('NotificationsService')
+ break
+ case 'settings':
+ serviceNav.replace('SettingsService')
+ break
+ }
+
+ changeNavigationBarColor(
+ isExpanded ? colors.primaryText : colors.primaryBackground,
+ undefined,
+ true,
+ )
+ },
+ [colors, serviceNav, isExpanded],
+ )
+
+ const onDrawerPress = useCallback(() => {
+ setIsExpanded((s) => !s)
+ changeNavigationBarColor(
+ isExpanded ? colors.primaryText : colors.primaryBackground,
+ undefined,
+ true,
+ )
+ }, [colors, isExpanded])
+
+ const onWalletIconPress = useCallback(() => {
+ if (currentService === 'wallets' && bottomSheetOpen) {
+ // TODO: Bring this back once we have the stickers page
+ // bottomSheetRef.current?.close()
+ return
+ }
+
+ serviceNav.replace('AccountsService')
+ bottomSheetRef.current?.expand()
+ }, [currentService, serviceNav, bottomSheetRef, bottomSheetOpen])
+
+ const onCloseSheet = useCallback(() => {
+ // if (currentService === '') return
+ // TODO: Bring this back once we have the stickers page
+ // bottomSheetRef.current?.close()
+ }, [])
+
+ const onChangeSheet = useCallback((index: number) => {
+ 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 (
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+ )
+}
+
+const Header = ({
+ title,
+ onDrawerPress,
+ onWalletIconPress,
+ walletsSelected,
+ onClose,
+}: {
+ title?: string
+ walletsSelected: boolean
+ onDrawerPress: () => void
+ onWalletIconPress: () => void
+ onClose: () => void
+}) => {
+ const spacing = useSpacing()
+ const { currentAccount } = useAccountStorage()
+
+ const titleAsWord = useMemo(() => {
+ if (!title || title === '') return ''
+ return title?.charAt(0).toUpperCase() + title?.slice(1)
+ }, [title])
+
+ return (
+
+
+
+
+ {titleAsWord}
+
+
+
+
+ {walletsSelected && (
+
+ )}
+
+
+
+
+ )
+}
+
+export default ServiceSheet
diff --git a/src/app/services/ServiceSheetNavigator.tsx b/src/app/services/ServiceSheetNavigator.tsx
new file mode 100644
index 000000000..4fb7d3652
--- /dev/null
+++ b/src/app/services/ServiceSheetNavigator.tsx
@@ -0,0 +1,113 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { useBorderRadii, useColors } from '@config/theme/themeHooks'
+import { StackNavigationOptions } from '@react-navigation/stack'
+import { useAppDispatch } from '@store/store'
+import { appSlice } from '@store/slices/appSlice'
+import ServiceSheet from './ServiceSheet'
+import WalletService from './WalletService'
+import HotspotService from './HotspotService'
+import AccountsService from './AccountsService'
+import GovernanceService from './GovernanceService'
+import BrowserService from './BrowserService'
+import SettingsService from './SettingsService'
+import NotificationsService from './NotificationsService'
+
+const ServiceSheetStack = createNativeStackNavigator()
+
+const ServiceSheetNavigator = () => {
+ const colors = useColors()
+ const borderRadii = useBorderRadii()
+ const [currentService, setCurrentService] = useState('wallet')
+ const dispatch = useAppDispatch()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ headerShown: false,
+ animation: 'none',
+ contentStyle: {
+ backgroundColor: colors['fg.white'],
+ borderTopLeftRadius: borderRadii['4xl'] + borderRadii['4xl'],
+ borderTopRightRadius: borderRadii['4xl'] + borderRadii['4xl'],
+ overflow: 'hidden',
+ },
+ } as StackNavigationOptions),
+ [borderRadii, colors],
+ )
+
+ 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 (
+
+ {
+ onFocus(target)
+ },
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ServiceSheetNavigator
diff --git a/src/app/services/SettingsService/index.tsx b/src/app/services/SettingsService/index.tsx
new file mode 100644
index 000000000..ef99c2b6e
--- /dev/null
+++ b/src/app/services/SettingsService/index.tsx
@@ -0,0 +1,8 @@
+import SettingsNavigator from '@features/settings/SettingsNavigator'
+import React from 'react'
+
+const SettingsService = () => {
+ return
+}
+
+export default SettingsService
diff --git a/src/app/services/WalletService/index.tsx b/src/app/services/WalletService/index.tsx
new file mode 100644
index 000000000..bb7528592
--- /dev/null
+++ b/src/app/services/WalletService/index.tsx
@@ -0,0 +1,69 @@
+import React, { useMemo } from 'react'
+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'
+import { StackNavigationProp } from '@react-navigation/stack'
+import WalletPage from './pages/WalletPage'
+import SendPage from './pages/SendPage'
+import TransactionsPage from './pages/TransactionsPage'
+import SwapPage from './pages/SwapPage'
+import ReceivePage from './pages/ReceivePage'
+
+export type PaymentRouteParam = {
+ payer?: string
+ payments?: string
+ payee?: string
+ amount?: string
+ memo?: string
+ netType?: string
+ defaultTokenType?: string
+ mint?: string
+}
+
+export type WalletServiceStackParamList = {
+ Receive: undefined
+ Send: undefined
+ Swap: undefined
+ Transactions: undefined
+ Wallet: undefined
+}
+
+export type WalletServiceNavigationProp =
+ StackNavigationProp
+
+const WalletService = () => {
+ const options = useMemo((): Array => {
+ return [
+ { name: 'Wallet', Icon: Wallet, component: WalletPage },
+ {
+ name: 'Receive',
+ Icon: Receive,
+ component: ReceivePage,
+ },
+ {
+ name: 'Send',
+ Icon: Send,
+ component: SendPage,
+ },
+ {
+ name: 'Swap',
+ Icon: Swap,
+ component: SwapPage,
+ },
+ {
+ name: 'Transactions',
+ Icon: Transactions,
+ component: TransactionsPage,
+ },
+ ]
+ }, [])
+
+ return
+}
+
+export default WalletService
diff --git a/src/app/services/WalletService/pages/ReceivePage/index.tsx b/src/app/services/WalletService/pages/ReceivePage/index.tsx
new file mode 100644
index 000000000..078419993
--- /dev/null
+++ b/src/app/services/WalletService/pages/ReceivePage/index.tsx
@@ -0,0 +1,101 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+import { ellipsizeAddress } from '@utils/accountUtils'
+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/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'
+import { FadeIn } from 'react-native-reanimated'
+import ScrollBox from '@components/ScrollBox'
+
+const ReceivePage = () => {
+ const { t } = useTranslation()
+ const wallet = useCurrentWallet()
+ const colors = useColors()
+ const copyText = useCopyText()
+
+ const onCopyAddress = useCallback(() => {
+ copyText({
+ message: t('generic.toClipboard'),
+ copyText: wallet?.toBase58() || '',
+ })
+ }, [copyText, wallet, t])
+
+ return (
+
+
+
+
+
+ {t('receivePage.title')}
+
+
+ {t('receivePage.subtitle')}
+
+
+
+
+
+
+
+
+ {t('receivePage.shareQr')}
+
+
+
+
+
+ {ellipsizeAddress(wallet?.toBase58() || '', {
+ numChars: 4,
+ })}
+
+
+
+ {t('receivePage.copyAddress')}
+
+
+
+
+
+ )
+}
+
+export default ReceivePage
diff --git a/src/app/services/WalletService/pages/SendPage/index.tsx b/src/app/services/WalletService/pages/SendPage/index.tsx
new file mode 100644
index 000000000..4c6ff0387
--- /dev/null
+++ b/src/app/services/WalletService/pages/SendPage/index.tsx
@@ -0,0 +1,44 @@
+import {
+ StackNavigationOptions,
+ StackNavigationProp,
+ createStackNavigator,
+} from '@react-navigation/stack'
+import React, { useMemo } from 'react'
+import { useColors } from '@config/theme/themeHooks'
+import PaymentScreen from '@features/payment/PaymentScreen'
+import AddressBookNavigator from '@features/addressBook/AddressBookNavigator'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import { FadeIn } from 'react-native-reanimated'
+
+export type SendStackParamList = {
+ PaymentScreen: undefined | PaymentRouteParam
+ AddressBook: undefined
+}
+
+export type SendNavigationProp = StackNavigationProp
+
+const SendStack = createStackNavigator()
+
+const SendPageNavigator = () => {
+ const colors = useColors()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ headerShown: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ } as StackNavigationOptions),
+ [colors],
+ )
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default SendPageNavigator
diff --git a/src/app/services/WalletService/pages/SwapPage/index.tsx b/src/app/services/WalletService/pages/SwapPage/index.tsx
new file mode 100644
index 000000000..fb9c8c9d0
--- /dev/null
+++ b/src/app/services/WalletService/pages/SwapPage/index.tsx
@@ -0,0 +1,14 @@
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import SwapNavigator from '@features/swaps/SwapNavigator'
+import React from 'react'
+import { FadeIn } from 'react-native-reanimated'
+
+const SwapPage = () => {
+ return (
+
+
+
+ )
+}
+
+export default SwapPage
diff --git a/src/app/services/WalletService/pages/TransactionsPage/index.tsx b/src/app/services/WalletService/pages/TransactionsPage/index.tsx
new file mode 100644
index 000000000..9576242d4
--- /dev/null
+++ b/src/app/services/WalletService/pages/TransactionsPage/index.tsx
@@ -0,0 +1,14 @@
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import ActivityNavigator from '@features/activity/ActivityNavigator'
+import React from 'react'
+import { FadeIn } from 'react-native-reanimated'
+
+const TransactionsPage = () => {
+ return (
+
+
+
+ )
+}
+
+export default TransactionsPage
diff --git a/src/app/services/WalletService/pages/WalletPage/index.tsx b/src/app/services/WalletService/pages/WalletPage/index.tsx
new file mode 100644
index 000000000..5d38b2801
--- /dev/null
+++ b/src/app/services/WalletService/pages/WalletPage/index.tsx
@@ -0,0 +1,113 @@
+import {
+ StackNavigationOptions,
+ StackNavigationProp,
+ createStackNavigator,
+} from '@react-navigation/stack'
+import React, { useMemo } from 'react'
+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/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 TokensTabs from '@features/wallet/TokensTabs'
+import { CompressedNFT } from '../../../../../types/solana'
+
+export type BurnRouteParam = {
+ address: string
+ amount?: string
+ memo?: string
+ isDelegate?: boolean
+ mint?: string
+}
+
+export type WalletStackParamList = {
+ TokensTabs: undefined
+ AccountTokenScreen: { mint: string }
+ AirdropScreen: { mint: string }
+ ConfirmPin: {
+ action: 'payment'
+ }
+ BurnScreen: BurnRouteParam
+ AccountManageTokenListScreen: undefined
+ PaymentQrScanner: undefined
+ NftDetailsScreen: {
+ collectable: CompressedNFT
+ }
+ CollectionScreen: {
+ collection: CompressedNFT[]
+ }
+ ManageCollectables: undefined
+ TransferCollectableScreen: {
+ collectable: CompressedNFT
+ }
+ TransferCompleteScreen: {
+ collectable: CompressedNFT
+ }
+}
+
+export type WalletNavigationProp = StackNavigationProp
+
+const WalletStack = createStackNavigator()
+
+const WalletPageNavigator = () => {
+ const colors = useColors()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ headerShown: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ } as StackNavigationOptions),
+ [colors],
+ )
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default WalletPageNavigator
diff --git a/src/app/services/serviceSheetTypes.ts b/src/app/services/serviceSheetTypes.ts
new file mode 100644
index 000000000..03074c235
--- /dev/null
+++ b/src/app/services/serviceSheetTypes.ts
@@ -0,0 +1,14 @@
+import { StackNavigationProp } from '@react-navigation/stack'
+
+export type ServiceSheetStackParamList = {
+ WalletService: undefined
+ HotspotService: undefined
+ AccountsService: undefined
+ GovernanceService: undefined
+ BrowserService: undefined
+ SettingsService: undefined
+ NotificationsService: undefined
+}
+
+export type ServiceSheetNavigationProp =
+ StackNavigationProp
diff --git a/src/assets/fonts/DMSans-Bold.ttf b/src/assets/fonts/DMSans-Bold.ttf
deleted file mode 100644
index 7fd94a28b..000000000
Binary files a/src/assets/fonts/DMSans-Bold.ttf and /dev/null differ
diff --git a/src/assets/fonts/DMSans-BoldItalic.ttf b/src/assets/fonts/DMSans-BoldItalic.ttf
deleted file mode 100644
index 6e1f86145..000000000
Binary files a/src/assets/fonts/DMSans-BoldItalic.ttf and /dev/null differ
diff --git a/src/assets/fonts/DMSans-Italic.ttf b/src/assets/fonts/DMSans-Italic.ttf
deleted file mode 100644
index bdda5a7a9..000000000
Binary files a/src/assets/fonts/DMSans-Italic.ttf and /dev/null differ
diff --git a/src/assets/fonts/DMSans-Medium.ttf b/src/assets/fonts/DMSans-Medium.ttf
deleted file mode 100644
index ded3caf9a..000000000
Binary files a/src/assets/fonts/DMSans-Medium.ttf and /dev/null differ
diff --git a/src/assets/fonts/DMSans-MediumItalic.ttf b/src/assets/fonts/DMSans-MediumItalic.ttf
deleted file mode 100644
index 8a2b876d5..000000000
Binary files a/src/assets/fonts/DMSans-MediumItalic.ttf and /dev/null differ
diff --git a/src/assets/fonts/DMSans-Regular.ttf b/src/assets/fonts/DMSans-Regular.ttf
deleted file mode 100644
index b3c3eda64..000000000
Binary files a/src/assets/fonts/DMSans-Regular.ttf and /dev/null differ
diff --git a/src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf b/src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf
new file mode 100644
index 000000000..fd997441d
Binary files /dev/null and b/src/assets/fonts/Figtree-Italic-VariableFont_wght.ttf differ
diff --git a/src/assets/fonts/Figtree-VariableFont_wght.ttf b/src/assets/fonts/Figtree-VariableFont_wght.ttf
new file mode 100644
index 000000000..06f9fe572
Binary files /dev/null and b/src/assets/fonts/Figtree-VariableFont_wght.ttf differ
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/accounts.png b/src/assets/images/accounts.png
new file mode 100644
index 000000000..5515942f1
Binary files /dev/null and b/src/assets/images/accounts.png differ
diff --git a/src/assets/images/accounts@2x.png b/src/assets/images/accounts@2x.png
new file mode 100644
index 000000000..0608a0304
Binary files /dev/null and b/src/assets/images/accounts@2x.png differ
diff --git a/src/assets/images/accounts@3x.png b/src/assets/images/accounts@3x.png
new file mode 100644
index 000000000..b65b49f2e
Binary files /dev/null and b/src/assets/images/accounts@3x.png differ
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/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/helium.png b/src/assets/images/helium.png
new file mode 100644
index 000000000..09c29afef
Binary files /dev/null and b/src/assets/images/helium.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/hotspot.svg b/src/assets/images/hotspot.svg
deleted file mode 100644
index 364fd0495..000000000
--- a/src/assets/images/hotspot.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/info.svg b/src/assets/images/info.svg
deleted file mode 100644
index f664e08ef..000000000
--- a/src/assets/images/info.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
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/receive.png b/src/assets/images/receive.png
new file mode 100644
index 000000000..522972225
Binary files /dev/null and b/src/assets/images/receive.png differ
diff --git a/src/assets/images/receive.svg b/src/assets/images/receive.svg
deleted file mode 100644
index 62c79fce4..000000000
--- a/src/assets/images/receive.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/images/receive@2x.png b/src/assets/images/receive@2x.png
new file mode 100644
index 000000000..73eab1ea6
Binary files /dev/null and b/src/assets/images/receive@2x.png differ
diff --git a/src/assets/images/receive@3x.png b/src/assets/images/receive@3x.png
new file mode 100644
index 000000000..9e65891a5
Binary files /dev/null and b/src/assets/images/receive@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/send.svg b/src/assets/images/send.svg
deleted file mode 100644
index 9d25ea8a1..000000000
--- a/src/assets/images/send.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/images/sendIcon.png b/src/assets/images/sendIcon.png
new file mode 100644
index 000000000..e8f1988c2
Binary files /dev/null and b/src/assets/images/sendIcon.png differ
diff --git a/src/assets/images/sendIcon@2x.png b/src/assets/images/sendIcon@2x.png
new file mode 100644
index 000000000..fadc7e148
Binary files /dev/null and b/src/assets/images/sendIcon@2x.png differ
diff --git a/src/assets/images/sendIcon@3x.png b/src/assets/images/sendIcon@3x.png
new file mode 100644
index 000000000..dd776d98f
Binary files /dev/null and b/src/assets/images/sendIcon@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/swapIcon.png b/src/assets/images/swapIcon.png
new file mode 100644
index 000000000..80099d464
Binary files /dev/null and b/src/assets/images/swapIcon.png differ
diff --git a/src/assets/images/swapIcon@2x.png b/src/assets/images/swapIcon@2x.png
new file mode 100644
index 000000000..523b5e54a
Binary files /dev/null and b/src/assets/images/swapIcon@2x.png differ
diff --git a/src/assets/images/swapIcon@3x.png b/src/assets/images/swapIcon@3x.png
new file mode 100644
index 000000000..afb766887
Binary files /dev/null and b/src/assets/images/swapIcon@3x.png differ
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/transactionIcon.png b/src/assets/images/transactionIcon.png
new file mode 100644
index 000000000..96443c654
Binary files /dev/null and b/src/assets/images/transactionIcon.png differ
diff --git a/src/assets/images/transactionIcon@2x.png b/src/assets/images/transactionIcon@2x.png
new file mode 100644
index 000000000..8b3a623a8
Binary files /dev/null and b/src/assets/images/transactionIcon@2x.png differ
diff --git a/src/assets/images/transactionIcon@3x.png b/src/assets/images/transactionIcon@3x.png
new file mode 100644
index 000000000..fb7a3cbd0
Binary files /dev/null and b/src/assets/images/transactionIcon@3x.png differ
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/voteSlide0.png b/src/assets/images/voteSlide0.png
index c154ea5fd..b7bfb43a5 100644
Binary files a/src/assets/images/voteSlide0.png and b/src/assets/images/voteSlide0.png differ
diff --git a/src/assets/images/voteSlide0@2x.png b/src/assets/images/voteSlide0@2x.png
index 91d8dff16..8deb472c2 100644
Binary files a/src/assets/images/voteSlide0@2x.png and b/src/assets/images/voteSlide0@2x.png differ
diff --git a/src/assets/images/voteSlide0@3x.png b/src/assets/images/voteSlide0@3x.png
index 3574574f3..e123c216d 100644
Binary files a/src/assets/images/voteSlide0@3x.png and b/src/assets/images/voteSlide0@3x.png differ
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/svgs/addressIcon.svg b/src/assets/svgs/addressIcon.svg
new file mode 100644
index 000000000..2d590c506
--- /dev/null
+++ b/src/assets/svgs/addressIcon.svg
@@ -0,0 +1,4 @@
+
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 84%
rename from src/assets/images/backArrow.svg
rename to src/assets/svgs/backArrow.svg
index 686cc76ac..54d175df9 100644
--- a/src/assets/images/backArrow.svg
+++ b/src/assets/svgs/backArrow.svg
@@ -1,3 +1,3 @@
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/svgs/bigAdd.svg b/src/assets/svgs/bigAdd.svg
new file mode 100644
index 000000000..3e7442f37
--- /dev/null
+++ b/src/assets/svgs/bigAdd.svg
@@ -0,0 +1,4 @@
+
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 85%
rename from src/assets/images/carotDownFull.svg
rename to src/assets/svgs/carotDownFull.svg
index 9248ed8cf..c0d66075c 100644
--- a/src/assets/images/carotDownFull.svg
+++ b/src/assets/svgs/carotDownFull.svg
@@ -1,3 +1,3 @@
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 65%
rename from src/assets/images/closeModal.svg
rename to src/assets/svgs/closeModal.svg
index bdce4e2fc..7d9741038 100644
--- a/src/assets/images/closeModal.svg
+++ b/src/assets/svgs/closeModal.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
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/svgs/collectables.svg b/src/assets/svgs/collectables.svg
new file mode 100644
index 000000000..cb342e52a
--- /dev/null
+++ b/src/assets/svgs/collectables.svg
@@ -0,0 +1,3 @@
+
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 99%
rename from src/assets/images/createAccount.svg
rename to src/assets/svgs/createAccount.svg
index 0971fb857..6c1370cf7 100644
--- a/src/assets/images/createAccount.svg
+++ b/src/assets/svgs/createAccount.svg
@@ -1,3 +1,3 @@
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/svgs/face.svg b/src/assets/svgs/face.svg
new file mode 100644
index 000000000..462843158
--- /dev/null
+++ b/src/assets/svgs/face.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
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 96%
rename from src/assets/images/flag.svg
rename to src/assets/svgs/flag.svg
index b77f3811c..c61d9e10a 100644
--- a/src/assets/images/flag.svg
+++ b/src/assets/svgs/flag.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
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 97%
rename from src/assets/images/hnt.svg
rename to src/assets/svgs/hnt.svg
index 2884b6a38..a2d92a914 100644
--- a/src/assets/images/hnt.svg
+++ b/src/assets/svgs/hnt.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
diff --git a/src/assets/svgs/hotspot.svg b/src/assets/svgs/hotspot.svg
new file mode 100644
index 000000000..e36c937c0
--- /dev/null
+++ b/src/assets/svgs/hotspot.svg
@@ -0,0 +1,3 @@
+
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/svgs/info.svg b/src/assets/svgs/info.svg
new file mode 100644
index 000000000..08aff22e0
--- /dev/null
+++ b/src/assets/svgs/info.svg
@@ -0,0 +1,5 @@
+
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 96%
rename from src/assets/images/iot.svg
rename to src/assets/svgs/iot.svg
index f66ebf56b..6cddcf055 100644
--- a/src/assets/images/iot.svg
+++ b/src/assets/svgs/iot.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
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 74%
rename from src/assets/images/lightningBolt.svg
rename to src/assets/svgs/lightningBolt.svg
index c8868a030..bf2b5f730 100644
--- a/src/assets/images/lightningBolt.svg
+++ b/src/assets/svgs/lightningBolt.svg
@@ -1,5 +1,5 @@
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 96%
rename from src/assets/images/mobile.svg
rename to src/assets/svgs/mobile.svg
index 83ece2b17..78025db91 100644
--- a/src/assets/images/mobile.svg
+++ b/src/assets/svgs/mobile.svg
@@ -1,4 +1,4 @@
\ No newline at end of file
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/svgs/receive.svg b/src/assets/svgs/receive.svg
new file mode 100644
index 000000000..3377903ad
--- /dev/null
+++ b/src/assets/svgs/receive.svg
@@ -0,0 +1,3 @@
+
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/svgs/send.svg b/src/assets/svgs/send.svg
new file mode 100644
index 000000000..55e00a5f1
--- /dev/null
+++ b/src/assets/svgs/send.svg
@@ -0,0 +1,3 @@
+
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/svgs/smallAdd.svg b/src/assets/svgs/smallAdd.svg
new file mode 100644
index 000000000..2803fa3ff
--- /dev/null
+++ b/src/assets/svgs/smallAdd.svg
@@ -0,0 +1,4 @@
+
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/svgs/swap.svg b/src/assets/svgs/swap.svg
new file mode 100644
index 000000000..26a4722a8
--- /dev/null
+++ b/src/assets/svgs/swap.svg
@@ -0,0 +1,3 @@
+
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/svgs/tokens.svg b/src/assets/svgs/tokens.svg
new file mode 100644
index 000000000..12190a8fc
--- /dev/null
+++ b/src/assets/svgs/tokens.svg
@@ -0,0 +1,3 @@
+
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/svgs/transactionsTabIcon.svg b/src/assets/svgs/transactionsTabIcon.svg
new file mode 100644
index 000000000..696575c61
--- /dev/null
+++ b/src/assets/svgs/transactionsTabIcon.svg
@@ -0,0 +1,3 @@
+
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 93%
rename from src/assets/images/userStar.svg
rename to src/assets/svgs/userStar.svg
index c78c2e9b1..05c8275c1 100644
--- a/src/assets/images/userStar.svg
+++ b/src/assets/svgs/userStar.svg
@@ -1,5 +1,5 @@
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/svgs/visibilityOff.svg b/src/assets/svgs/visibilityOff.svg
new file mode 100644
index 000000000..2702013f1
--- /dev/null
+++ b/src/assets/svgs/visibilityOff.svg
@@ -0,0 +1,12 @@
+
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/svgs/wallet.svg b/src/assets/svgs/wallet.svg
new file mode 100644
index 000000000..a49426d9d
--- /dev/null
+++ b/src/assets/svgs/wallet.svg
@@ -0,0 +1,3 @@
+
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 da001ceb3..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'
@@ -34,7 +34,7 @@ const AccountButton = ({
backgroundColor: backgroundColorProps,
...boxProps
}: Props) => {
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
const colors = useColors()
const { triggerImpact } = useHaptic()
@@ -58,21 +58,26 @@ const AccountButton = ({
>
{!!subtitle && (
-
+
{subtitle}
)}
-
+
{title}
diff --git a/src/components/AccountIcon.tsx b/src/components/AccountIcon.tsx
index 414e10311..72dc47872 100644
--- a/src/components/AccountIcon.tsx
+++ b/src/components/AccountIcon.tsx
@@ -1,12 +1,22 @@
import React, { memo, useMemo } from 'react'
import Jazzicon, { IJazziconProps } from 'react-native-jazzicon'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useAsync } from 'react-async-hook'
import { getJazzSeed } from '../utils/accountUtils'
+import { ImageBox } from '.'
type Props = { address?: string; size: number } & Omit<
IJazziconProps,
'seed' | 'size'
>
const AccountIcon = ({ address, ...jazzIconProps }: Props) => {
+ const { getAvatar, currentAccount } = useAccountStorage()
+
+ const { result: avatar } = useAsync(async () => {
+ if (!address) return
+ return getAvatar(address)
+ }, [address, currentAccount])
+
const seed = useMemo(() => {
if (!address) return null
return getJazzSeed(address)
@@ -14,6 +24,17 @@ const AccountIcon = ({ address, ...jazzIconProps }: Props) => {
if (!seed) return null
+ if (avatar) {
+ return (
+
+ )
+ }
+
return
}
export default memo(AccountIcon)
diff --git a/src/components/AccountListItem.tsx b/src/components/AccountListItem.tsx
index 8e25dd25d..cc7584e05 100644
--- a/src/components/AccountListItem.tsx
+++ b/src/components/AccountListItem.tsx
@@ -1,11 +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 '@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 = {
@@ -14,8 +16,14 @@ type Props = {
onPress?: (account: CSAccount) => void
disabled?: boolean
}
-const AccountListItem = ({ selected, account, onPress, disabled }: Props) => {
- const { primary } = useColors()
+const AccountListItem = ({
+ selected,
+ account,
+ onPress,
+ disabled,
+ ...rest
+}: Props & BoxProps) => {
+ const { primaryText } = useColors()
const handlePress = useCallback(() => onPress?.(account), [account, onPress])
@@ -26,34 +34,35 @@ const AccountListItem = ({ selected, account, onPress, disabled }: Props) => {
return (
-
+
{formatAccountAlias(account)}
-
+
{ellipsizeAddress(address || '')}
{selected && (
-
+
)}
diff --git a/src/components/AccountSelector.tsx b/src/components/AccountSelector.tsx
index 8b7866148..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
@@ -38,14 +38,17 @@ const AccountSelector = forwardRef(
useImperativeHandle(ref, () => ({ show, showAccountTypes }))
const bottomSheetModalRef = useRef(null)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const { m, xl } = useSpacing()
+ const { backgroundStyle } = useOpacity('bg.tertiary', 1)
+ const spacing = useSpacing()
const [accountsType, setAccountsTypes] = useState('all')
const snapPoints = useMemo(() => ['60%', '80%'], [])
const colors = useColors()
- const sheetHandleStyle = useMemo(() => ({ padding: m }), [m])
- const flatListContainerStyle = useMemo(() => ({ paddingBottom: xl }), [xl])
+ const sheetHandleStyle = useMemo(() => ({ padding: spacing[4] }), [spacing])
+ const flatListContainerStyle = useMemo(
+ () => ({ paddingBottom: spacing[8] }),
+ [spacing],
+ )
const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
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 6a9c39397..5013d4ede 100644
--- a/src/components/AddressBookSelector.tsx
+++ b/src/components/AddressBookSelector.tsx
@@ -2,34 +2,32 @@
import React, {
forwardRef,
memo,
- ReactNode,
Ref,
useCallback,
useImperativeHandle,
- useMemo,
useRef,
useState,
} from 'react'
-import {
+import BottomSheet, {
BottomSheetBackdrop,
- BottomSheetModal,
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet'
import { useNavigation } from '@react-navigation/native'
-import { BoxProps } from '@shopify/restyle'
-import { useColors, useOpacity, useSpacing } from '@theme/themeHooks'
-import { Theme } from '@theme/theme'
-import useBackHandler from '@hooks/useBackHandler'
-import ContactsList from '../features/addressBook/ContactsList'
-import { HomeNavigationProp } from '../features/home/homeTypes'
-import Box from './Box'
-import { CSAccount } from '../storage/cloudStorage'
+import { BoxProps, ThemeProvider } from '@shopify/restyle'
+import { lightTheme, Theme } from '@config/theme/theme'
+import ContactsList from '@features/addressBook/ContactsList'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { Portal } from '@gorhom/portal'
+import { useTranslation } from 'react-i18next'
+import { SendNavigationProp } from 'src/app/services/WalletService/pages/SendPage'
+import { AddressBookNavigationProp } from '@features/addressBook/addressBookTypes'
+import HeliumBottomSheet from './HeliumBottomSheet'
+import { SafeAreaBox, Text } from '.'
export type AddressBookRef = {
showAddressBook: (opts: { address?: string; index?: number }) => void
}
type Props = {
- children: ReactNode
hideCurrentAccount?: boolean
onContactSelected: (opts: {
contact: CSAccount
@@ -39,35 +37,31 @@ type Props = {
} & BoxProps
const AddressBookSelector = forwardRef(
(
- { children, onContactSelected, hideCurrentAccount, ...boxProps }: Props,
+ { onContactSelected, hideCurrentAccount }: Props,
ref: Ref,
) => {
useImperativeHandle(ref, () => ({ showAddressBook }))
- const bottomSheetModalRef = useRef(null)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const { m } = useSpacing()
- const snapPoints = useMemo(() => ['70%', '90%'], [])
- const sheetHandleStyle = useMemo(() => ({ padding: m }), [m])
- const homeNav = useNavigation()
+ const bottomSheetModalRef = useRef(null)
+ const { t } = useTranslation()
+ const navigation = useNavigation<
+ SendNavigationProp & AddressBookNavigationProp
+ >()
const [address, setAddress] = useState()
const [index, setIndex] = useState()
- const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
- const colors = useColors()
const showAddressBook = useCallback(
(opts: { address?: string; index?: number }) => {
setAddress(opts.address)
setIndex(opts.index)
- bottomSheetModalRef.current?.present()
- setIsShowing(true)
+ bottomSheetModalRef.current?.expand()
},
- [setIsShowing],
+ [],
)
const handleContactSelected = useCallback(
(contact: CSAccount) => {
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
onContactSelected({ contact, prevAddress: address, index })
},
[address, index, onContactSelected],
@@ -76,50 +70,58 @@ const AddressBookSelector = forwardRef(
const renderBackdrop = useCallback(
(props) => (
+ >
+
+
+ {t('addressBookSelector.title')}
+
+
+
),
- [],
+ [t],
)
const handleAddNewContact = useCallback(() => {
- homeNav.navigate('AddNewContact')
- }, [homeNav])
-
- const handleIndicatorStyle = useMemo(() => {
- return {
- backgroundColor: colors.secondaryText,
- }
- }, [colors.secondaryText])
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ;(navigation as any).navigate('AddressBook', {
+ screen: 'AddNewContact',
+ initial: false,
+ params: undefined,
+ })
+ bottomSheetModalRef.current?.close()
+ }, [navigation])
return (
-
- {children}
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
)
},
)
diff --git a/src/components/AutoGasBanner.tsx b/src/components/AutoGasBanner.tsx
index d789b7342..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'
@@ -168,15 +168,15 @@ const Banner = ({ onLayout, ...rest }: BannerProps) => {
return (
@@ -188,8 +188,8 @@ const Banner = ({ onLayout, ...rest }: BannerProps) => {
)}
& {
const BackButton = ({
color = 'primaryText',
onPress,
- paddingHorizontal = 'lx',
+ paddingHorizontal = '7',
hitSlop,
...props
}: Props) => {
diff --git a/src/components/BackScreen.tsx b/src/components/BackScreen.tsx
index 7dd38f126..e9a0a2715 100644
--- a/src/components/BackScreen.tsx
+++ b/src/components/BackScreen.tsx
@@ -1,12 +1,12 @@
/* eslint-disable react/jsx-props-no-spreading */
import { useNavigation } from '@react-navigation/native'
import { BoxProps } from '@shopify/restyle'
-import React, { memo, useMemo } from 'react'
+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 { 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'
@@ -32,6 +32,7 @@ type Props = BoxProps & {
onTrailingIconPress?: () => void
headerTopMargin?: Spacing
rootBackgroundColor?: Color
+ onBack?: () => void
}
const BackScreen = ({
@@ -41,7 +42,7 @@ const BackScreen = ({
edges,
onClose,
hideBack,
- headerHorizontalPadding = 'lx',
+ headerHorizontalPadding = '7',
onLayout,
onHeaderLayout,
title,
@@ -51,12 +52,22 @@ const BackScreen = ({
onTrailingIconPress,
headerTopMargin,
rootBackgroundColor,
+ onBack,
...rest
}: Props) => {
const navigation = useNavigation()
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
+ const colors = useColors()
const isAndroid = useMemo(() => Platform.OS === 'android', [])
+ const onBackHandler = useCallback(() => {
+ if (onBack) {
+ onBack()
+ } else {
+ navigation.goBack()
+ }
+ }, [navigation, onBack])
+
return (
@@ -76,21 +87,23 @@ const BackScreen = ({
alignItems="center"
justifyContent="center"
>
- {title}
+
+ {title}
+
{!hideBack && (
)}
{onClose && (
)}
@@ -98,17 +111,16 @@ const BackScreen = ({
{TrailingIcon && (
-
+
)}
- {/* if padding is not set, set it to 'lx' , if padding set to 'none' , set it to 0 */}
-
+
{children}
diff --git a/src/components/BackgroundFill.tsx b/src/components/BackgroundFill.tsx
index 282e3feca..a5e47b8a4 100644
--- a/src/components/BackgroundFill.tsx
+++ b/src/components/BackgroundFill.tsx
@@ -1,13 +1,13 @@
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
const BackgroundFill = ({ opacity, backgroundColor, ...boxProps }: Props) => (
{
+ 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 903d68184..5997bf82e 100644
--- a/src/components/BlurActionSheet.tsx
+++ b/src/components/BlurActionSheet.tsx
@@ -1,17 +1,16 @@
-import React, { memo, useCallback, useMemo, useRef, useState } from 'react'
-import {
- BottomSheetModal,
- BottomSheetModalProvider,
- BottomSheetScrollView,
-} from '@gorhom/bottom-sheet'
-import { LayoutChangeEvent } from 'react-native'
-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 { useOpacity } from '@theme/themeHooks'
-import CustomBlurBackdrop from './CustomBlurBackdrop'
-import SafeAreaBox from './SafeAreaBox'
-import { wh } from '../utils/layout'
+import { ThemeProvider } from '@shopify/restyle'
+import { lightTheme } from '@config/theme/theme'
+import { useTranslation } from 'react-i18next'
+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
@@ -21,9 +20,10 @@ type Props = {
}
const BlurActionSheet = ({ title, open, children, onClose }: Props) => {
- const bottomSheetModalRef = useRef(null)
- const [contentHeight, setContentHeight] = useState(0)
- const { backgroundStyle } = useOpacity('black400', 0.4)
+ const bottomSheetModalRef = useRef(null)
+ const { t } = useTranslation()
+ const { top, bottom } = useSafeAreaInsets()
+ const spacing = useSpacing()
const handleOnClose = useCallback(() => {
if (onClose) {
@@ -33,59 +33,67 @@ const BlurActionSheet = ({ title, open, children, onClose }: Props) => {
useAsync(async () => {
if (open) {
- await bottomSheetModalRef.current?.present()
+ await bottomSheetModalRef.current?.expand()
} else {
- await bottomSheetModalRef.current?.dismiss()
+ await bottomSheetModalRef.current?.close()
}
}, [open])
- const snapPoints = useMemo(() => {
- let maxHeight: number | string = '75%'
- if (contentHeight > 0) {
- maxHeight = Math.min(wh * 0.75, contentHeight)
- }
-
- return [maxHeight]
- }, [contentHeight])
-
const renderBackdrop = useCallback(
(props) => (
-
+ >
+
+
+ {t('blurActionSheet.selectAnOption')}
+
+
+
),
- [handleOnClose, title],
+ [handleOnClose, title, top, t],
)
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
-
- const handleContentLayout = useCallback((e: LayoutChangeEvent) => {
- setContentHeight(e.nativeEvent.layout.height + 40)
- }, [])
-
return (
-
-
-
-
+
+
+
+
{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/Bullet.tsx b/src/components/Bullet.tsx
index 5a0c28ab8..5c52fba41 100644
--- a/src/components/Bullet.tsx
+++ b/src/components/Bullet.tsx
@@ -12,13 +12,19 @@ const Bullet = ({ children, color = 'black', style = {} }: Props) => (
-
+
•
-
+
{children}
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 717db24d5..92a579f13 100644
--- a/src/components/ButtonPressable.tsx
+++ b/src/components/ButtonPressable.tsx
@@ -4,14 +4,14 @@ 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'
+import CircleLoader from './CircleLoader'
type Props = BoxProps & {
- backgroundColor?: Color
backgroundColorDisabled?: Color
backgroundColorOpacity?: number
backgroundColorDisabledOpacity?: number
@@ -34,6 +34,10 @@ type Props = BoxProps & {
style?: ViewStyle
LeadingComponent?: React.ReactNode
TrailingComponent?: React.ReactNode
+ iconProps?: SvgProps
+ loading?: boolean
+ customLoadingColor?: Color
+ customLoadingColorDisabled?: Color
}
const ButtonPressable = ({
@@ -61,6 +65,10 @@ const ButtonPressable = ({
height = 60,
LeadingComponent,
TrailingComponent,
+ iconProps,
+ loading,
+ customLoadingColor = 'primaryText',
+ customLoadingColorDisabled = 'text.disabled',
...boxProps
}: Props) => {
const [pressed, setPressed] = useState(false)
@@ -116,12 +124,12 @@ const ButtonPressable = ({
}
if (pressed || selected) {
return backgroundStyle(
- backgroundColorPressed || backgroundColor || 'white',
+ backgroundColorPressed || (backgroundColor as Color) || 'primaryText',
backgroundColorOpacityPressed,
)
}
if (backgroundColor) {
- return backgroundStyle(backgroundColor, backgroundColorOpacity)
+ return backgroundStyle(backgroundColor as Color, backgroundColorOpacity)
}
}, [
backgroundStyle,
@@ -136,6 +144,12 @@ const ButtonPressable = ({
backgroundColorOpacity,
])
+ const circleLoaderColor = useMemo(() => {
+ if (disabled) return customLoadingColorDisabled
+ if (loading) return customLoadingColor
+ return 'primaryText'
+ }, [disabled, loading, customLoadingColor, customLoadingColorDisabled])
+
return (
- {LeadingComponent && {LeadingComponent}}
+ {loading ? (
+
+
+
+ ) : (
+ <>
+ {LeadingComponent && {LeadingComponent}}
- {title && (
-
- {title}
-
+ {title && (
+
+ {title}
+
+ )}
+ {Icon && }
+ {TrailingComponent && (
+ {TrailingComponent}
+ )}
+ >
)}
- {Icon && }
- {TrailingComponent && {TrailingComponent}}
)
diff --git a/src/components/Card.tsx b/src/components/Card.tsx
index eb38c6845..122f1e531 100644
--- a/src/components/Card.tsx
+++ b/src/components/Card.tsx
@@ -4,7 +4,7 @@ import {
createVariant,
} from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import Box from './Box'
const Card = createRestyleComponent<
diff --git a/src/components/CardSkeleton.tsx b/src/components/CardSkeleton.tsx
index 10f9b806c..5b2f7a394 100644
--- a/src/components/CardSkeleton.tsx
+++ b/src/components/CardSkeleton.tsx
@@ -8,13 +8,13 @@ export const CardSkeleton: React.FC<{ height: number }> = ({ height }) => {
return (
diff --git a/src/components/CircleLoader.tsx b/src/components/CircleLoader.tsx
index 1c1f9553e..032f42568 100644
--- a/src/components/CircleLoader.tsx
+++ b/src/components/CircleLoader.tsx
@@ -2,8 +2,9 @@
import React, { memo, useRef, useEffect } from 'react'
import { Animated, Easing } from 'react-native'
import { BoxProps } from '@shopify/restyle'
-import CircleLoaderSvg from '@assets/images/circleLoader.svg'
-import { Color, Theme } from '@theme/theme'
+import CircleLoaderSvg from '@assets/svgs/circleLoader.svg'
+import { Color, Theme } from '@config/theme/theme'
+import { useColors } from '@config/theme/themeHooks'
import Box from './Box'
import Text from './Text'
@@ -16,11 +17,12 @@ const CircleLoader = ({
text,
loaderSize = 30,
minHeight,
- color = 'white',
+ color = 'primaryText',
...props
}: Props) => {
const rotateAnim = useRef(new Animated.Value(0))
const opacityAnim = useRef(new Animated.Value(0))
+ const colors = useColors()
const anim = () => {
Animated.loop(
@@ -72,14 +74,18 @@ const CircleLoader = ({
],
}}
>
-
+
{text && (
{text}
diff --git a/src/components/CloseButton.tsx b/src/components/CloseButton.tsx
index 0e27229b3..1127ac765 100644
--- a/src/components/CloseButton.tsx
+++ b/src/components/CloseButton.tsx
@@ -1,20 +1,26 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { memo } from 'react'
-import Close from '@assets/images/closeModal.svg'
+import Close from '@assets/svgs/closeModal.svg'
import { GestureResponderEvent, Insets } from 'react-native'
import { BoxProps } from '@shopify/restyle'
-import { useColors } from '@theme/themeHooks'
-import { Theme } from '@theme/theme'
+import { useColors } from '@config/theme/themeHooks'
+import { Color, Theme } from '@config/theme/theme'
import IconPressedContainer from './IconPressedContainer'
import Box from './Box'
export type CloseButtonProps = {
onPress?: ((event: GestureResponderEvent) => void) | null | undefined
hitSlop?: Insets | undefined
+ color?: Color
} & BoxProps
-const CloseButton = ({ onPress, hitSlop, ...props }: CloseButtonProps) => {
- const { primaryText } = useColors()
+const CloseButton = ({
+ onPress,
+ hitSlop,
+ color = 'primaryText',
+ ...props
+}: CloseButtonProps) => {
+ const colors = useColors()
return (
{
idleOpacity={0.75}
activeOpacity={0.9}
>
-
+
)
diff --git a/src/components/ConfirmPinScreen.tsx b/src/components/ConfirmPinScreen.tsx
index b7804ec8b..c37c1b859 100644
--- a/src/components/ConfirmPinScreen.tsx
+++ b/src/components/ConfirmPinScreen.tsx
@@ -3,18 +3,16 @@ import { useTranslation } from 'react-i18next'
import { RouteProp, useRoute, useNavigation } from '@react-navigation/native'
import { useAsync } from 'react-async-hook'
import * as LocalAuthentication from 'expo-local-authentication'
+import { WalletStackParamList } from '@services/WalletService/pages/WalletPage'
+import { SendNavigationProp } from '@services/WalletService/pages/SendPage'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import ConfirmPinView from './ConfirmPinView'
-import {
- HomeNavigationProp,
- HomeStackParamList,
-} from '../features/home/homeTypes'
-import { useAppStorage } from '../storage/AppStorageProvider'
-type Route = RouteProp
+type Route = RouteProp
const ConfirmPinScreen = () => {
const route = useRoute()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const { params } = route
const { t } = useTranslation()
const { pin } = useAppStorage()
@@ -22,7 +20,7 @@ const ConfirmPinScreen = () => {
const pinSuccess = useCallback(async () => {
switch (params.action) {
case 'payment':
- navigation.replace('PaymentScreen')
+ navigation.navigate('PaymentScreen')
break
}
}, [navigation, params.action])
diff --git a/src/components/ConfirmPinView.tsx b/src/components/ConfirmPinView.tsx
index a3a9c6583..08f159e17 100644
--- a/src/components/ConfirmPinView.tsx
+++ b/src/components/ConfirmPinView.tsx
@@ -86,26 +86,31 @@ const ConfirmPinView = ({
{title}
-
+
{subtitle}
-
+
{clearable && onCancel && (
-
- {t('auth.signOut')}
+
+
+ {t('auth.signOut')}
+
)}
diff --git a/src/components/CopyAddress.tsx b/src/components/CopyAddress.tsx
index b2f56648e..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'
@@ -40,21 +40,21 @@ const CopyAddress = ({ address, ...boxProps }: Props) => {
-
+
{t('generic.copy')}
diff --git a/src/components/CopyAddressPill.tsx b/src/components/CopyAddressPill.tsx
index 9babf7f19..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'
@@ -34,28 +34,30 @@ const CopyAddressPill = ({ ...rest }: BoxProps) => {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
- paddingVertical: spacing.s,
- paddingHorizontal: spacing.m,
+ paddingVertical: spacing[2],
+ paddingHorizontal: spacing[4],
} as ViewStyle
}, [spacing])
return (
{ellipsizeAddress(currentAccount?.solanaAddress || '', {
numChars: 6,
diff --git a/src/components/CountdownTimer.tsx b/src/components/CountdownTimer.tsx
index 9d9372e46..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'
@@ -88,12 +88,12 @@ const CountdownTimer = forwardRef(
{...boxProps}
>
-
+
{title || ''}
diff --git a/src/components/Dot.tsx b/src/components/Dot.tsx
index 6a13ae42e..49dceb95a 100644
--- a/src/components/Dot.tsx
+++ b/src/components/Dot.tsx
@@ -8,11 +8,11 @@ const Dot = ({ filled }: Props) => {
)
}
diff --git a/src/components/DynamicQrScanner.tsx b/src/components/DynamicQrScanner.tsx
index 1402a3870..644180cfa 100644
--- a/src/components/DynamicQrScanner.tsx
+++ b/src/components/DynamicQrScanner.tsx
@@ -6,6 +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 '@config/theme/themeHooks'
import { CameraScannerLayout } from './CameraScannerLayout'
import Box from './Box'
import BackScreen from './BackScreen'
@@ -20,6 +21,7 @@ const DynamicQrScanner = ({ onBarCodeScanned, progress }: Props) => {
const [hasPermission, setHasPermission] = useState()
const navigation = useNavigation()
const { showOKCancelAlert } = useAlert()
+ const colors = useColors()
const { t } = useTranslation()
useEffect(() => {
@@ -60,7 +62,7 @@ const DynamicQrScanner = ({ onBarCodeScanned, progress }: Props) => {
}
return (
-
+
{/* if permission is not granted, show a black screen and notice alert modal */}
{hasPermission !== true && }
@@ -69,7 +71,10 @@ const DynamicQrScanner = ({ onBarCodeScanned, progress }: Props) => {
{
position="absolute"
bottom="10%"
alignSelf="center"
- paddingHorizontal="s"
+ paddingHorizontal="1"
>
-
+
{t('keystone.payment.scanTxQrcodeScreenSubtitle3')}
diff --git a/src/components/FabButton.tsx b/src/components/FabButton.tsx
index e4069167d..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,9 +51,10 @@ type IconName =
| 'info'
| 'questionMark'
| 'browseVoters'
-
+ | 'expand'
+ | 'settings'
+ | 'arrowLeft'
type Props = BoxProps & {
- backgroundColor?: Color
backgroundColorOpacity?: number
backgroundColorPressed?: Color
backgroundColorOpacityPressed?: number
@@ -91,13 +94,13 @@ const ButtonPressable = ({
const backgroundColorStyle = useMemo(() => {
if (pressed) {
return backgroundStyle(
- backgroundColorPressed || backgroundColor || 'white',
+ backgroundColorPressed || (backgroundColor as Color) || 'primaryText',
backgroundColorOpacityPressed,
)
}
if (!pressed && backgroundColor) {
- return backgroundStyle(backgroundColor, backgroundColorOpacity)
+ return backgroundStyle(backgroundColor as Color, backgroundColorOpacity)
}
}, [
pressed,
@@ -110,7 +113,7 @@ const ButtonPressable = ({
if (title) {
return (
-
+
setPressed(true)}
@@ -124,8 +127,8 @@ const ButtonPressable = ({
alignItems="center"
justifyContent="center"
flexDirection={reverse ? 'row-reverse' : 'row'}
- paddingHorizontal="m"
- borderRadius="round"
+ paddingHorizontal="4"
+ borderRadius="full"
{...containerProps}
>
{icon && (
@@ -139,7 +142,7 @@ const ButtonPressable = ({
)}
{
style={{ transform: [{ rotate: '270deg' }] }}
/>
)
+ case 'arrowLeft':
+ return (
+
+ )
case 'arrowDown':
return
case 'fatArrowUp':
@@ -288,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 187c73e97..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
@@ -19,23 +19,23 @@ const FinePrint = (boxProps: Props) => {
const onPressTOS = useCallback(() => Linking.openURL(TERMS_OF_SERVICE), [])
return (
-
+
{t('finePrint.body')}{' '}
-
+
{t('settings.sections.finePrint.termsOfService')}{' '}
-
+
{t('generic.and')}{' '}
-
+
{t('settings.sections.finePrint.privacyPolicy')}
-
+
{t('generic.period')}
diff --git a/src/components/GlobalError.tsx b/src/components/GlobalError.tsx
index 3c8848a4e..319b99c50 100644
--- a/src/components/GlobalError.tsx
+++ b/src/components/GlobalError.tsx
@@ -1,13 +1,13 @@
-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'
import { useTranslation } from 'react-i18next'
-import { ScrollView } from 'react-native'
import Box from './Box'
import ButtonPressable from './ButtonPressable'
import SafeAreaBox from './SafeAreaBox'
import Text from './Text'
+import ScrollBox from './ScrollBox'
export const GlobalError = ({
error,
@@ -30,20 +30,25 @@ export const GlobalError = ({
return (
-
+
{t('crash.title')}
-
+
{t('crash.subTitle')}
-
-
+
+
{error.message}
-
+
{error.stack}
-
+
@@ -63,11 +68,11 @@ export const GlobalError = ({
width="100%"
title={t('crash.resetApp')}
onPress={resetErrorBoundary}
- borderRadius="round"
- backgroundColor="white"
+ borderRadius="full"
+ backgroundColor="base.white"
backgroundColorOpacityPressed={0.7}
titleColorDisabled="secondaryText"
- titleColor="black"
+ titleColor="base.black"
/>
diff --git a/src/components/HNTKeyboard.tsx b/src/components/HNTKeyboard.tsx
index 88924e98e..387ca993e 100644
--- a/src/components/HNTKeyboard.tsx
+++ b/src/components/HNTKeyboard.tsx
@@ -1,7 +1,6 @@
-import PaymentArrow from '@assets/images/paymentArrow.svg'
-import {
+import PaymentArrow from '@assets/svgs/paymentArrow.svg'
+import BottomSheet, {
BottomSheetBackdrop,
- BottomSheetModal,
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet'
import { Portal } from '@gorhom/portal'
@@ -10,14 +9,13 @@ import {
useOwnedAmount,
useSolOwnedAmount,
} from '@helium/helium-react-hooks'
-import useBackHandler from '@hooks/useBackHandler'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
-import { BoxProps } from '@shopify/restyle'
+import { BoxProps, ThemeProvider } from '@shopify/restyle'
import { NATIVE_MINT } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
-import { useOpacity, 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,
@@ -33,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'
@@ -46,6 +44,7 @@ import { KeypadInput } from './KeypadButton'
import SafeAreaBox from './SafeAreaBox'
import Text from './Text'
import TouchableOpacityBox from './TouchableOpacityBox'
+import HeliumBottomSheet from './HeliumBottomSheet'
type ShowOptions = {
payer?: CSAccount | null
@@ -66,7 +65,6 @@ type Props = {
networkFee?: BN
// Ensure a minimum number of tokens, useful for swapping sol
minTokens?: BN
- children: ReactNode
handleVisible?: (visible: boolean) => void
onConfirmBalance: (opts: {
balance: BN
@@ -74,7 +72,6 @@ type Props = {
payee?: string
index?: number
}) => void
- usePortal?: boolean
allowOverdraft?: boolean
// allow this keyboard to be used with BN values of a mint other
// than just owned amount
@@ -84,24 +81,20 @@ const HNTKeyboardSelector = forwardRef(
(
{
minTokens,
- children,
onConfirmBalance,
handleVisible,
mint,
networkFee,
- usePortal = false,
allowOverdraft = false,
actionableAmount,
- ...boxProps
}: Props,
ref: Ref,
) => {
useImperativeHandle(ref, () => ({ show, hide }))
const decimals = useMint(mint)?.info?.decimals
const { t } = useTranslation()
- const bottomSheetModalRef = useRef(null)
+ const bottomSheetModalRef = useRef(null)
const { symbol, loading: loadingMeta } = useMetaplexMetadata(mint)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
const [value, setValue] = useState('0')
const [originalValue, setOriginalValue] = useState('')
const [payee, setPayee] = useState()
@@ -111,7 +104,6 @@ const HNTKeyboardSelector = forwardRef(
const [containerHeight, setContainerHeight] = useState(0)
const [headerHeight, setHeaderHeight] = useState(0)
const containerStyle = useSafeTopPaddingStyle('android')
- const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
const wallet = useCurrentWallet()
const { amount: balanceForMintToken } = useOwnedAmount(wallet, mint)
@@ -185,14 +177,16 @@ const HNTKeyboardSelector = forwardRef(
: undefined
setValue(val || '0')
- bottomSheetModalRef.current?.present()
- setIsShowing(true)
+ // wait 1 render cycle to expand
+ setTimeout(() => {
+ bottomSheetModalRef.current?.expand()
+ }, 100)
},
- [handleVisible, setIsShowing, decimals],
+ [handleVisible, decimals],
)
const hide = useCallback(() => {
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
}, [])
const handleHeaderLayout = useCallback(
@@ -249,21 +243,13 @@ const HNTKeyboardSelector = forwardRef(
const BackdropWrapper = useCallback(
({ children: backdropChildren }: { children: ReactNode }) => {
- if (!usePortal) {
- return (
-
- {backdropChildren}
-
- )
- }
-
return (
{backdropChildren}
)
},
- [containerStyle, usePortal],
+ [containerStyle],
)
const renderBackdrop = useCallback(
@@ -276,9 +262,9 @@ const HNTKeyboardSelector = forwardRef(
{...props}
>
-
+
{!loadingMeta && (
-
+
{t('hntKeyboard.enterAmount', {
ticker: symbol || '',
})}
@@ -287,7 +273,7 @@ const HNTKeyboardSelector = forwardRef(
{payer && (
<>
@@ -296,7 +282,7 @@ const HNTKeyboardSelector = forwardRef(
address={payer?.address || payer?.solanaAddress}
/>
-
+
>
@@ -306,9 +292,9 @@ const HNTKeyboardSelector = forwardRef(
)}
{payer && balanceForMint && typeof decimals !== 'undefined'
? t('hntKeyboard.hntAvailable', {
@@ -340,33 +326,38 @@ const HNTKeyboardSelector = forwardRef(
const renderHandle = useCallback(() => {
if (!payer) {
- return
+ return
}
return (
-
+
{t('payment.max')}
@@ -389,7 +380,7 @@ const HNTKeyboardSelector = forwardRef(
}, [networkFee, payer, valueAsBalance, balanceForMint])
const handleConfirm = useCallback(() => {
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
if (!valueAsBalance || typeof decimals === 'undefined') return
@@ -399,7 +390,7 @@ const HNTKeyboardSelector = forwardRef(
max: maxEnabled,
index: paymentIndex,
})
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
}, [
valueAsBalance,
maxEnabled,
@@ -411,7 +402,7 @@ const HNTKeyboardSelector = forwardRef(
const handleCancel = useCallback(() => {
setValue(originalValue)
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
}, [originalValue])
const handleDecimal = useCallback(() => {
@@ -464,58 +455,43 @@ const HNTKeyboardSelector = forwardRef(
const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
- const handleModalDismiss = useCallback(() => {
- handleDismiss()
- handleVisible?.(false)
- }, [handleDismiss, handleVisible])
-
- const PortalWrapper = useCallback(
- ({ children: portalChildren }: { children: ReactNode }) => {
- if (usePortal) {
- return {portalChildren}
- }
- return <>{portalChildren}>
- },
- [usePortal],
- )
-
return (
-
-
+
+
-
{`${value || '0'} ${symbol || ''}`}
{payer && networkFee && (
{t('hntKeyboard.fee', {
value: networkFee && humanReadable(networkFee, 9),
@@ -525,26 +501,26 @@ const HNTKeyboardSelector = forwardRef(
-
-
+
+
{t('generic.cancel')}
@@ -554,25 +530,25 @@ const HNTKeyboardSelector = forwardRef(
minHeight={66}
alignItems="center"
justifyContent="center"
- borderRadius="round"
+ borderRadius="full"
flex={1}
backgroundColor={
allowOverdraft || hasSufficientBalance
- ? 'surface'
- : 'grey300'
+ ? 'primaryText'
+ : 'gray.300'
}
disabled={!allowOverdraft ? !hasSufficientBalance : false}
>
- {t('generic.confirm')}
+
+ {t('generic.confirm')}
+
-
- {!usePortal && children}
+
-
- {usePortal && children}
-
+
+
)
},
)
diff --git a/src/components/HandleBasic.tsx b/src/components/HandleBasic.tsx
index 142c46bbf..394e72a51 100644
--- a/src/components/HandleBasic.tsx
+++ b/src/components/HandleBasic.tsx
@@ -1,17 +1,12 @@
/* 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
export default (boxProps: Props) => (
-
-
+
+
)
diff --git a/src/components/HeliumActionSheet.tsx b/src/components/HeliumActionSheet.tsx
index 3268cd49b..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,
@@ -24,7 +24,7 @@ import HeliumActionSheetItem, {
import Text, { TextProps } from './Text'
import Box from './Box'
import TouchableOpacityBox from './TouchableOpacityBox'
-import HeliumBottomSheet from './HeliumBottomSheet'
+import HeliumBottomActionSheet from './HeliumBottomActionSheet'
type Props = BoxProps & {
data: Array
@@ -57,7 +57,7 @@ const HeliumActionSheet = forwardRef(
title,
prefix,
iconVariant = 'carot',
- iconColor: carotColor = 'primary',
+ iconColor: carotColor = 'primaryText',
buttonProps,
initialValue,
textProps,
@@ -75,7 +75,7 @@ const HeliumActionSheet = forwardRef(
const [data, setData] = useState>([])
const { t } = useTranslation()
const colors = useColors()
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
useEffect(() => {
setData(propsData)
@@ -148,20 +148,21 @@ const HeliumActionSheet = forwardRef(
const footer = useMemo(() => {
return (
-
+
{t('generic.cancel')}
@@ -192,7 +193,8 @@ const HeliumActionSheet = forwardRef(
{!!prefix && (
{buttonTitle}
@@ -232,7 +235,7 @@ const HeliumActionSheet = forwardRef(
return (
{displayText}
-
{footer}
-
+
)
},
diff --git a/src/components/HeliumActionSheetItem.tsx b/src/components/HeliumActionSheetItem.tsx
index 1c4a9e98d..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'
@@ -33,9 +33,9 @@ const HeliumActionSheetItem = ({
const colors = useColors()
const color = useMemo((): Color => {
- if (selected) return 'purple500'
+ if (selected) return 'purple.500'
if (disabled) return 'secondaryText'
- return 'surfaceSecondaryText'
+ return 'secondaryText'
}, [disabled, selected])
return (
@@ -48,7 +48,8 @@ const HeliumActionSheetItem = ({
>
{!!Icon && }
& {
+ children?: React.ReactNode
+ hideHeaderBorder?: boolean
+ isVisible: boolean
+ onClose: () => void
+ sheetHeight?: number
+ title?: string
+}
+
+const HeliumBottomActionSheet = ({
+ children,
+ hideHeaderBorder = false,
+ isVisible,
+ onClose,
+ sheetHeight = 260,
+ title,
+}: Props) => {
+ const colors = useColors()
+ const offset = useSharedValue(0)
+
+ const animatedStyles = useAnimatedStyle(() => {
+ return {
+ transform: [{ translateY: offset.value + sheetHeight }],
+ }
+ })
+
+ const animate = useCallback(
+ (val: number) => {
+ offset.value = withSpring(val, {
+ damping: 80,
+ overshootClamping: true,
+ restDisplacementThreshold: 0.1,
+ restSpeedThreshold: 0.1,
+ stiffness: 500,
+ })
+ },
+ [offset],
+ )
+
+ const handleClose = useCallback(async () => {
+ onClose()
+ }, [onClose])
+
+ useDisappear(handleClose)
+
+ useEffect(() => {
+ if (isVisible) {
+ offset.value = 0
+ animate(-sheetHeight)
+ }
+ }, [animate, isVisible, offset, sheetHeight])
+
+ return (
+
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+ {children}
+
+
+
+ )
+}
+
+export default memo(HeliumBottomActionSheet)
diff --git a/src/components/HeliumBottomSheet.tsx b/src/components/HeliumBottomSheet.tsx
index b5544b9f9..7c12781c3 100644
--- a/src/components/HeliumBottomSheet.tsx
+++ b/src/components/HeliumBottomSheet.tsx
@@ -1,118 +1,82 @@
-import React, { memo, useCallback, useEffect } from 'react'
-import { BoxProps } from '@shopify/restyle'
-import Close from '@assets/images/close.svg'
-import { Modal } from 'react-native'
+import React, { forwardRef, useMemo } from 'react'
+import BottomSheet, { BottomSheetProps } from '@gorhom/bottom-sheet'
import {
- useAnimatedStyle,
- useSharedValue,
- withSpring,
-} from 'react-native-reanimated'
-import { Theme } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
-import useDisappear from '@hooks/useDisappear'
-import Text from './Text'
-import Box from './Box'
-import TouchableOpacityBox from './TouchableOpacityBox'
-import BlurBox from './BlurBox'
-import { ReAnimatedBox } from './AnimatedBox'
+ useBackgroundStyle,
+ useBorderRadii,
+ useColors,
+ useSpacing,
+} from '@config/theme/themeHooks'
+import { wh } from '@utils/layout'
+import { Platform, StyleProp, ViewStyle } from 'react-native'
+import { useSharedValue } from 'react-native-reanimated'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
-type Props = BoxProps & {
- children?: React.ReactNode
- hideHeaderBorder?: boolean
- isVisible: boolean
- onClose: () => void
- sheetHeight?: number
- title?: string
-}
+const HeliumBottomSheet = forwardRef(
+ (props, ref) => {
+ const { children, ...rest } = props
+ const { top } = useSafeAreaInsets()
+ const spacing = useSpacing()
+ const colors = useColors()
+ const borderRadii = useBorderRadii()
+ const bottomSheetStyle = useBackgroundStyle('primaryText')
+ const listAnimatedPos = useSharedValue(wh - 100)
-const HeliumBottomSheet = ({
- children,
- hideHeaderBorder = false,
- isVisible,
- onClose,
- sheetHeight = 260,
- title,
-}: Props) => {
- const colors = useColors()
- const offset = useSharedValue(0)
+ const snapPoints = useMemo(() => {
+ if (Platform.OS === 'ios') {
+ return [wh - top - spacing[20]]
+ }
- const animatedStyles = useAnimatedStyle(() => {
- return {
- transform: [{ translateY: offset.value + sheetHeight }],
- }
- })
+ return [wh - top - spacing[20] - spacing[2]]
+ }, [top, spacing])
- const animate = useCallback(
- (val: number) => {
- offset.value = withSpring(val, {
- damping: 80,
- overshootClamping: true,
- restDisplacementThreshold: 0.1,
- restSpeedThreshold: 0.1,
- stiffness: 500,
- })
- },
- [offset],
- )
+ const handleIndicatorStyle = useMemo(() => {
+ return {
+ width: 90,
+ height: 4,
+ backgroundColor: colors['base.black'],
+ }
+ }, [colors])
- const handleClose = useCallback(async () => {
- onClose()
- }, [onClose])
+ const handleStyle = useMemo(
+ () =>
+ ({
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ opacity: 0.1,
+ } as StyleProp),
+ [],
+ )
- useDisappear(handleClose)
+ const backgroundStyle = useMemo(
+ () =>
+ ({
+ ...bottomSheetStyle,
+ height: '100%',
+ borderRadius: borderRadii['4xl'] + borderRadii['4xl'],
+ backgroundColor: colors['fg.white'],
+ } as StyleProp),
+ [bottomSheetStyle, borderRadii, colors],
+ )
- useEffect(() => {
- if (isVisible) {
- offset.value = 0
- animate(-sheetHeight)
- }
- }, [animate, isVisible, offset, sheetHeight])
+ return (
+
+ {children}
+
+ )
+ },
+)
- return (
-
-
-
-
-
-
-
- {title}
-
-
-
-
-
- {children}
-
-
-
- )
-}
-
-export default memo(HeliumBottomSheet)
+export default HeliumBottomSheet
diff --git a/src/components/IconPressedContainer.tsx b/src/components/IconPressedContainer.tsx
index 93f75ffb4..045f83fec 100644
--- a/src/components/IconPressedContainer.tsx
+++ b/src/components/IconPressedContainer.tsx
@@ -10,7 +10,7 @@ import {
} from 'react-native'
import { useAnimatedStyle, withSpring } from 'react-native-reanimated'
import useHaptic from '@hooks/useHaptic'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { ReAnimatedBox } from './AnimatedBox'
export const ICON_CONTAINER_SIZE = 44
diff --git a/src/components/ImageBox.tsx b/src/components/ImageBox.tsx
index e633db0cd..ca70bad29 100644
--- a/src/components/ImageBox.tsx
+++ b/src/components/ImageBox.tsx
@@ -1,7 +1,7 @@
import { createBox } from '@shopify/restyle'
import { Image, ImageProps } from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
const ImageBox = createBox(Image)
diff --git a/src/components/IndeterminateProgressBar.tsx b/src/components/IndeterminateProgressBar.tsx
index 5fc7b1ed8..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'
@@ -59,18 +59,18 @@ const IndeterminateProgressBar = ({ ...rest }: BoxProps) => {
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 398dca8ea..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'
@@ -16,10 +16,13 @@ type Props = {
}
const KeypadButton = ({ value, onPress }: Props) => {
- const { backgroundStyle: goldBackgroundStyle } = useOpacity('gold', 0.29)
- const { gold, surfaceSecondaryText } = useColors()
+ const { backgroundStyle: goldBackgroundStyle } = useOpacity(
+ 'yellow.500',
+ 0.29,
+ )
+ const colors = useColors()
const { t } = useTranslation()
- const hitSlop = useHitSlop('m')
+ const hitSlop = useHitSlop('4')
const getBackgroundColorStyle = useCallback(
(pressed: boolean) => {
@@ -38,11 +41,11 @@ const KeypadButton = ({ value, onPress }: Props) => {
if (typeof value === 'number') {
return (
{value}
@@ -59,16 +62,18 @@ const KeypadButton = ({ value, onPress }: Props) => {
justifyContent="center"
alignItems="center"
>
-
+
)
case 'decimal':
return (
{decimalSeparator}
@@ -76,12 +81,12 @@ const KeypadButton = ({ value, onPress }: Props) => {
case 'clear':
return (
{t('generic.clear')}
@@ -89,17 +94,17 @@ const KeypadButton = ({ value, onPress }: Props) => {
case 'cancel':
return (
{t('generic.cancel')}
)
}
},
- [gold, surfaceSecondaryText, t, value],
+ [colors, t, value],
)
return (
@@ -112,7 +117,7 @@ const KeypadButton = ({ value, onPress }: Props) => {
height="100%"
width="100%"
aspectRatio={1}
- borderRadius="round"
+ borderRadius="full"
maxWidth={80}
maxHeight={80}
hitSlop={hitSlop}
diff --git a/src/components/Link.tsx b/src/components/Link.tsx
index 8ff094f83..fc999aebd 100644
--- a/src/components/Link.tsx
+++ b/src/components/Link.tsx
@@ -4,7 +4,7 @@ import Text from './Text'
type Props = { children?: ReactNode; href?: string }
const Link = ({ children, href }: Props) => (
- href && Linking.openURL(href)}>
+ href && Linking.openURL(href)}>
{children}
)
diff --git a/src/components/ListItem.tsx b/src/components/ListItem.tsx
index 48ea2edc5..ab3cbfd72 100644
--- a/src/components/ListItem.tsx
+++ b/src/components/ListItem.tsx
@@ -1,11 +1,11 @@
import React from 'react'
-import CheckMarkFill from '@assets/images/checkmarkFill.svg'
-import { useColors } from '@theme/themeHooks'
-import { Color } 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'
import Text from './Text'
-import { TouchableOpacityBoxProps } from './TouchableOpacityBox'
import TouchableContainer from './TouchableContainer'
export const LIST_ITEM_HEIGHT = 70
@@ -21,7 +21,7 @@ export type ListItemProps = {
hasDivider?: boolean
hasPressedState?: boolean
hitSlop?: Insets
-} & TouchableOpacityBoxProps
+} & BoxProps
const ListItem = ({
Icon,
@@ -49,26 +49,28 @@ const ListItem = ({
alignItems="center"
flex={1}
flexDirection="row"
- paddingVertical="m"
- borderBottomColor="black900"
+ paddingVertical="4"
+ borderBottomColor="primaryBackground"
borderBottomWidth={hasDivider ? 1 : 0}
onPress={handlePress}
hasPressedState={hasPressedState}
{...rest}
>
{Icon && Icon}
-
- {title}
+
+
+ {title}
+
{subtitle && (
-
+
{subtitle}
)}
-
+
{selected ? (
) => (
+
+)
+
+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 8bac36c36..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'
@@ -17,34 +17,34 @@ export const Markdown: React.FC<{ markdown?: string }> = ({ markdown }) => {
markdown={markdown}
style={{
hr: {
- marginTop: theme.spacing.m,
+ marginTop: theme.spacing[4],
},
blockquote: {
- ...theme.textVariants.body2,
+ ...theme.textVariants.textSmRegular,
color: theme.colors.primaryText,
backgroundColor: 'transparent',
},
body: {
- ...theme.textVariants.body2,
+ ...(theme.textVariants.textSmRegular as any),
color: theme.colors.primaryText,
},
heading1: {
- ...theme.textVariants.subtitle1,
+ ...theme.textVariants.textXlMedium,
color: theme.colors.primaryText,
- paddingTop: theme.spacing.ms,
- paddingBottom: theme.spacing.ms,
+ paddingTop: theme.spacing[4],
+ paddingBottom: theme.spacing[4],
},
heading2: {
- ...theme.textVariants.subtitle2,
+ ...theme.textVariants.textSmMedium,
color: theme.colors.primaryText,
- paddingTop: theme.spacing.ms,
- paddingBottom: theme.spacing.ms,
+ paddingTop: theme.spacing[4],
+ paddingBottom: theme.spacing[4],
},
heading3: {
- ...theme.textVariants.subtitle3,
+ ...theme.textVariants.textXsMedium,
color: theme.colors.primaryText,
- paddingTop: theme.spacing.ms,
- paddingBottom: theme.spacing.ms,
+ paddingTop: theme.spacing[4],
+ paddingBottom: theme.spacing[4],
},
}}
>
diff --git a/src/components/MemoInput.tsx b/src/components/MemoInput.tsx
index 0ad10a2ad..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'
@@ -76,7 +76,11 @@ const MemoInput = ({ onChangeText, value, ...boxProps }: Props) => {
}}
/>
-
+
{t('payment.memoBytes', {
used: bytesUsed,
total: MEMO_MAX_BYTES,
diff --git a/src/components/MenuButton.tsx b/src/components/MenuButton.tsx
new file mode 100644
index 000000000..36c4d8a70
--- /dev/null
+++ b/src/components/MenuButton.tsx
@@ -0,0 +1,107 @@
+import React from 'react'
+import { useAnimatedStyle, withTiming } from 'react-native-reanimated'
+import { ReAnimatedBox } from '.'
+import TouchableOpacityBox from './TouchableOpacityBox'
+
+type MenuButtonProps = {
+ isOpen: boolean
+ onPress: () => void
+}
+
+const MenuButton = ({ isOpen, onPress }: MenuButtonProps) => {
+ const firstBoxAnimatedStyle = useAnimatedStyle(() => {
+ if (isOpen) {
+ // Rotate 45 degrees to form the first part of the X
+ return {
+ transform: [
+ { rotate: withTiming('45deg') },
+ {
+ translateY: withTiming(12),
+ },
+ ],
+ width: withTiming(33.87),
+ }
+ }
+ return {
+ transform: [
+ { rotate: withTiming('0deg') },
+ {
+ translateY: withTiming(0),
+ },
+ ],
+ width: withTiming(28.87),
+ }
+ }, [isOpen])
+
+ const secondBoxAnimatedStyle = useAnimatedStyle(() => {
+ if (isOpen) {
+ // Set opacity to 0 to hide the second part of the hamburger menu
+ return {
+ opacity: withTiming(0),
+ }
+ }
+
+ return {
+ opacity: withTiming(1),
+ }
+ }, [isOpen])
+
+ const thirdBoxAnimatedStyle = useAnimatedStyle(() => {
+ if (isOpen) {
+ // Rotate -45 degrees to form the third part of the X
+ return {
+ transform: [
+ { rotate: withTiming('-45deg') },
+ {
+ translateX: withTiming(2),
+ },
+ {
+ translateY: withTiming(-14),
+ },
+ ],
+ width: withTiming(33.87),
+ }
+ }
+
+ return {
+ transform: [
+ { rotate: withTiming('0deg') },
+ {
+ translateX: withTiming(0),
+ },
+ {
+ translateY: withTiming(0),
+ },
+ ],
+ width: withTiming(12.02),
+ }
+ }, [isOpen])
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default MenuButton
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 ab4bdcbd5..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,
@@ -59,7 +59,7 @@ const NavBarItem = ({
key={value}
onPress={onPress}
onLayout={onLayout}
- marginRight="none"
+ marginRight="0"
hitSlop={hitSlop}
alignItems="center"
flexGrow={1}
@@ -67,10 +67,10 @@ const NavBarItem = ({
>
@@ -79,7 +79,7 @@ const NavBarItem = ({
{hasBadge && (
@@ -127,7 +127,7 @@ const NavBar = ({
onItemLongPress,
...containerProps
}: Props) => {
- const hitSlop = useVerticalHitSlop('l')
+ const hitSlop = useVerticalHitSlop('6')
const [itemRects, setItemRects] = useState>()
const offset = useSharedValue(null)
@@ -189,8 +189,12 @@ const NavBar = ({
])
return (
-
-
+
+
{items}
diff --git a/src/components/NetworkAwareStatusBar.tsx b/src/components/NetworkAwareStatusBar.tsx
deleted file mode 100644
index b0c00f688..000000000
--- a/src/components/NetworkAwareStatusBar.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react'
-import { StatusBar } from 'react-native'
-import { useColors, useColorScheme } from '@theme/themeHooks'
-
-const NetworkAwareStatusBar = () => {
- const colors = useColors()
- const theme = useColorScheme()
-
- return (
-
- )
-}
-
-export default NetworkAwareStatusBar
diff --git a/src/components/Pill.tsx b/src/components/Pill.tsx
index 0af433008..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'
@@ -14,6 +14,7 @@ type Color =
| 'iotGreen'
| 'mobileBlue'
| 'hntBlue'
+ | 'quinary'
export const Pill = memo(
({
text,
@@ -30,68 +31,79 @@ export const Pill = memo(
}) => {
const colorDefs = {
blue: {
- border: 'blueBorder',
- background: 'blue950',
- text: 'blue500',
+ border: 'blue.300',
+ background: 'blue.950',
+ text: 'blue.500',
},
green: {
- border: 'greenBorder',
- background: 'green950',
- text: 'green500',
+ border: 'green.300',
+ background: 'green.950',
+ text: 'green.500',
},
red: {
- border: 'redBorder',
- background: 'matchaRed950',
- text: 'matchaRed500',
+ border: 'ros.300',
+ background: 'ros.950',
+ text: 'error.500',
},
orange: {
- border: 'orangeBorder',
- background: 'orange950',
- text: 'orange500',
+ border: 'orange.300',
+ background: 'orange.950',
+ text: 'orange.500',
},
black: {
- background: 'black',
- text: 'white',
- border: 'black',
+ background: 'base.black',
+ text: 'base.white',
+ border: 'base.black',
},
hntBlue: {
- background: 'hntBlue',
- text: 'white',
- border: 'black',
+ background: 'purple.500',
+ text: 'base.white',
+ border: 'purple.500',
},
iotGreen: {
background: 'iotGreen',
- text: 'white',
- border: 'black',
+ text: 'base.white',
+ border: 'iotGreen',
},
mobileBlue: {
- background: 'mobileBlue',
- text: 'white',
- border: 'black',
+ background: 'blue.600',
+ text: 'base.white',
+ border: 'blue.600',
+ },
+ quinary: {
+ background: 'fg.quinary-400',
+ text: 'primaryBackground',
+ border: 'fg.quinary-400',
},
}
return (
{Icon ? (
-
+
) : null}
{text ? (
{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 bdc2f4710..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(() => {
@@ -46,21 +48,30 @@ const ProgressBar = ({
-
-
-
+
+
+
+
+
+ {withLabel && (
+
+ {`Progress: ${progressIn}%`}
+
+ )}
)
}
diff --git a/src/components/RadioButton.tsx b/src/components/RadioButton.tsx
index aa3c31699..bcf6e3cc8 100644
--- a/src/components/RadioButton.tsx
+++ b/src/components/RadioButton.tsx
@@ -16,18 +16,18 @@ const RadioButton: React.FC = ({
}) => {
return (
onClick()}
@@ -35,11 +35,16 @@ const RadioButton: React.FC = ({
- onClick()} color="white">
+ onClick()}
+ color="primaryText"
+ >
{label}
diff --git a/src/components/RevealWords.tsx b/src/components/RevealWords.tsx
index 44900ec38..294303b9d 100644
--- a/src/components/RevealWords.tsx
+++ b/src/components/RevealWords.tsx
@@ -6,12 +6,13 @@ import { ReAnimatedBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import { FlatList } from 'react-native'
-import { useColors, useSpacing } from '@theme/themeHooks'
-import CopyAddress from '@assets/images/copyAddress.svg'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import CopyAddress from '@assets/svgs/copyAddress.svg'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import useCopyText from '@hooks/useCopyText'
import useHaptic from '@hooks/useHaptic'
import { FadeIn } from 'react-native-reanimated'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
type Props = {
mnemonic: string[]
@@ -24,6 +25,7 @@ const RevealWords = ({ mnemonic, onDone, ListHeaderComponent }: Props) => {
const { secondaryText } = useColors()
const copyText = useCopyText()
const { triggerImpact } = useHaptic()
+ const { bottom } = useSafeAreaInsets()
const handleCopySeedPhrase = useCallback(() => {
triggerImpact('light')
@@ -38,24 +40,26 @@ const RevealWords = ({ mnemonic, onDone, ListHeaderComponent }: Props) => {
({ item, index }: { item: string; index: number }) => {
return (
{`${index + 1}. `}
{
const contentContainerStyle = useMemo(
() => ({
flexGrow: 1,
- paddingHorizontal: spacing.l,
+ paddingHorizontal: spacing[5],
}),
[spacing],
)
@@ -85,13 +89,13 @@ const RevealWords = ({ mnemonic, onDone, ListHeaderComponent }: Props) => {
justifyContent="center"
alignItems="center"
flexDirection="row"
- marginTop="m"
- marginBottom="xl"
+ marginTop="4"
+ marginBottom="8"
>
{
@@ -131,6 +135,7 @@ const RevealWords = ({ mnemonic, onDone, ListHeaderComponent }: Props) => {
ListFooterComponentStyle={{
flexGrow: 1,
justifyContent: 'flex-end',
+ paddingBottom: bottom,
}}
renderItem={renderItem}
contentContainerStyle={contentContainerStyle}
diff --git a/src/components/RewardItem.tsx b/src/components/RewardItem.tsx
index e33e4e3d7..197d06330 100644
--- a/src/components/RewardItem.tsx
+++ b/src/components/RewardItem.tsx
@@ -1,9 +1,8 @@
-import RewardBG from '@assets/images/rewardBg.svg'
import { useMint } from '@helium/helium-react-hooks'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { humanReadable } from '@utils/solanaUtils'
import BN from 'bn.js'
import React, { memo, useMemo } from 'react'
@@ -28,29 +27,27 @@ const RewardItem = ({ mint, amount, hasMore, ...rest }: RewardItemProps) => {
return (
-
-
-
-
{pendingRewardsString}
-
+
{symbol}
diff --git a/src/components/SafeAreaBox.tsx b/src/components/SafeAreaBox.tsx
index 1b33c79af..9b4aa7f6d 100644
--- a/src/components/SafeAreaBox.tsx
+++ b/src/components/SafeAreaBox.tsx
@@ -1,7 +1,7 @@
import { createBox } from '@shopify/restyle'
import { Platform } from 'react-native'
import { Edge, SafeAreaView } from 'react-native-safe-area-context'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
const SafeAreaBox = createBox>(
SafeAreaView,
diff --git a/src/components/ScrollBox.tsx b/src/components/ScrollBox.tsx
new file mode 100644
index 000000000..1e4d64abf
--- /dev/null
+++ b/src/components/ScrollBox.tsx
@@ -0,0 +1,14 @@
+import { createBox } from '@shopify/restyle'
+import { ReactNode } from 'react'
+import { Theme } from '@config/theme/theme'
+import { ScrollViewProps } from 'react-native'
+import { ScrollView } from 'react-native-gesture-handler'
+
+const ScrollBox = createBox<
+ Theme,
+ ScrollViewProps & {
+ children?: ReactNode
+ }
+>(ScrollView)
+
+export default ScrollBox
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 33134ecc1..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, Color, 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'
@@ -28,7 +28,7 @@ const SearchInput = ({
...boxProps
}: Props) => {
const {
- regular: { borderRadius, padding, color },
+ regular: { borderRadius, padding },
} = useInputVariants()
const colors = useColors()
@@ -40,29 +40,32 @@ const SearchInput = ({
return (
-
+
)
diff --git a/src/components/SecretKeyWarningScreen.tsx b/src/components/SecretKeyWarningScreen.tsx
index f39cfb654..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 { ScrollView, View } from 'react-native'
-import InfoWarning from '@assets/images/customWarning.svg'
+import { View } from 'react-native'
+import InfoWarning from '@assets/svgs/customWarning.svg'
import { useTranslation } from 'react-i18next'
import Animated, {
runOnJS,
@@ -8,20 +8,20 @@ import Animated, {
useSharedValue,
withTiming,
} from 'react-native-reanimated'
-import globalStyles from '@theme/globalStyles'
-import { useColors } from '@theme/themeHooks'
-import { useNavigation } from '@react-navigation/native'
+import globalStyles from '@config/theme/globalStyles'
+import { useColors } from '@config/theme/themeHooks'
import Text from './Text'
import Box from './Box'
import ButtonPressable from './ButtonPressable'
+import { BackScreen } from '.'
+import ScrollBox from './ScrollBox'
const SecretKeyWarningScreen = ({ children }: { children: ReactNode }) => {
const { t } = useTranslation()
- const navigation = useNavigation()
const [secondsPassed, setSecondsPassed] = useState(0)
const animValue = useSharedValue(1)
const [animationComplete, setAnimationComplete] = useState(false)
- const { primaryBackground, red500 } = useColors()
+ const { primaryBackground, ...colors } = useColors()
useEffect(() => {
// set interval to update text every second
@@ -34,10 +34,6 @@ const SecretKeyWarningScreen = ({ children }: { children: ReactNode }) => {
}
}, [])
- const goBack = useCallback(() => {
- navigation.goBack()
- }, [navigation])
-
const animationCompleted = useCallback(() => {
setAnimationComplete(true)
}, [])
@@ -71,7 +67,7 @@ const SecretKeyWarningScreen = ({ children }: { children: ReactNode }) => {
{children}
{!animationComplete && (
- {
justifyContent: 'center',
}}
>
-
+
-
-
-
- {t('secretKeyWarningScreen.title')}
-
+
+
+
+
+ {t('secretKeyWarningScreen.title')}
+
-
- {t('secretKeyWarningScreen.body')}
-
+
+ {t('secretKeyWarningScreen.body')}
+
-
+
-
-
-
- {t('secretKeyWarningScreen.youMayContinueInSeconds', {
- seconds: 5 - secondsPassed,
- })}
-
-
-
+
+ {t('secretKeyWarningScreen.youMayContinueInSeconds', {
+ seconds: 5 - secondsPassed,
+ })}
+
+
+
+
)}
diff --git a/src/components/SegmentedControl.tsx b/src/components/SegmentedControl.tsx
new file mode 100644
index 000000000..4fdd8bb04
--- /dev/null
+++ b/src/components/SegmentedControl.tsx
@@ -0,0 +1,195 @@
+import React, {
+ FC,
+ Ref,
+ forwardRef,
+ memo,
+ useCallback,
+ useImperativeHandle,
+ useMemo,
+ useState,
+} from 'react'
+import { BoxProps } from '@shopify/restyle'
+import { GestureResponderEvent, LayoutChangeEvent } from 'react-native'
+import { SvgProps } from 'react-native-svg'
+import { useColors } from '@config/theme/themeHooks'
+import { useAnimatedStyle, withTiming } from 'react-native-reanimated'
+import { Theme } from '../config/theme/theme'
+import { Box, ReAnimatedBox, Text } from '.'
+import TouchableOpacityBox from './TouchableOpacityBox'
+
+type Option = {
+ value: string | number
+ label: string
+ Icon?: FC
+ iconProps?: SvgProps
+}
+
+const SegmentedItem = ({
+ option,
+ selected,
+ 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)
+
+ const onLayout = useCallback(
+ (e: LayoutChangeEvent) => {
+ onSetWidth(e.nativeEvent.layout.width)
+ },
+ [onSetWidth],
+ )
+
+ const initialBackgroundColor = useMemo(
+ () => (selected ? 'primaryText' : 'transparent'),
+ [selected],
+ )
+
+ const backgroundColor = useMemo(() => {
+ if (!hasTouched) return initialBackgroundColor
+
+ return 'transparent'
+ }, [initialBackgroundColor, hasTouched])
+
+ const onPressHandler = useCallback(
+ (event: GestureResponderEvent) => {
+ setHasTouched(true)
+ if (onSelected) {
+ onSelected(event)
+ }
+ },
+ [onSelected],
+ )
+
+ return (
+
+ {option.Icon && (
+
+ )}
+
+ {option.label}
+
+
+ )
+}
+export type SegmentedControlRef = {
+ selectedIndex: number
+}
+
+type Props = {
+ options: Option[]
+ onItemSelected: (index: number) => void
+ fullWidth?: boolean
+ size?: 'sm' | 'md'
+} & BoxProps
+
+const SegmentedControl = forwardRef(
+ (
+ { options, onItemSelected, fullWidth, size = 'sm', ...boxProps }: Props,
+ ref: Ref,
+ ) => {
+ const [selectedIndex, setSelectedIndex] = useState(0)
+ const [hasTouched, setHasTouched] = useState(false)
+
+ useImperativeHandle(ref, () => ({ selectedIndex }))
+
+ const [optionWidths, setOptionWidths] = useState(
+ Array(options.length).fill(0),
+ )
+
+ const itemWidth = useMemo(
+ () => optionWidths[selectedIndex],
+ [optionWidths, selectedIndex],
+ )
+
+ const handleItemSelected = useCallback(
+ (index: number) => () => {
+ setHasTouched(true)
+ setSelectedIndex(index)
+ onItemSelected(index)
+ },
+ [onItemSelected],
+ )
+
+ const leftPosition = useMemo(() => {
+ return optionWidths
+ .slice(0, selectedIndex)
+ .reduce((acc, width) => (selectedIndex === 0 ? 0 : acc + width), 0)
+ }, [optionWidths, selectedIndex])
+
+ const onSetWidth = useCallback(
+ (index: number) => (width: number) => {
+ setOptionWidths((prev) => {
+ const newOptionWidths = [...prev]
+ newOptionWidths[index] = width
+ return newOptionWidths
+ })
+ },
+ [],
+ )
+
+ const animatedStyle = useAnimatedStyle(() => {
+ return {
+ left: withTiming(leftPosition, { duration: 200 }),
+ width: withTiming(itemWidth, { duration: hasTouched ? 200 : 0 }),
+ }
+ }, [leftPosition, itemWidth, hasTouched])
+
+ return (
+
+
+
+ {options.map((option, index) => (
+
+ ))}
+
+
+ )
+ },
+)
+
+export default memo(SegmentedControl)
diff --git a/src/components/Select.tsx b/src/components/Select.tsx
index 3710c2a2e..5c3a93062 100644
--- a/src/components/Select.tsx
+++ b/src/components/Select.tsx
@@ -1,73 +1,144 @@
-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 (
<>
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}
+
+ )}
-
+
setFiltersOpen(false)}
>
- <>
- {options.map((option) => (
- {
- onValueChange(option.value)
- setFiltersOpen(false)
- }}
- selected={value === option.value}
- hasPressedState={false}
- />
- ))}
- >
+ `${item.value}`}
+ ListHeaderComponent={renderHeader}
+ />
>
)
diff --git a/src/components/ServiceNavBar.tsx b/src/components/ServiceNavBar.tsx
new file mode 100644
index 000000000..ffe8abbed
--- /dev/null
+++ b/src/components/ServiceNavBar.tsx
@@ -0,0 +1,200 @@
+import React, {
+ FC,
+ memo,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react'
+import { Insets, LayoutChangeEvent, LayoutRectangle } from 'react-native'
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+ withSpring,
+} from 'react-native-reanimated'
+import { SvgProps } from 'react-native-svg'
+import { useColors, useVerticalHitSlop } from '@config/theme/themeHooks'
+import Box from './Box'
+import TouchableOpacityBox, {
+ TouchableOpacityBoxProps,
+} from './TouchableOpacityBox'
+
+export const NavBarHeight = 76
+
+export type ServiceNavBarOption = {
+ value: string
+ Icon: FC
+ iconProps?: SvgProps
+}
+
+const NavBarItem = ({
+ selected,
+ onLayout,
+ onPress,
+ onLongPress,
+ hitSlop,
+ Icon,
+ value,
+ iconProps,
+}: {
+ selected: boolean
+ onPress: () => void
+ onLongPress?: () => void
+ onLayout: (event: LayoutChangeEvent) => void
+ hitSlop: Insets | undefined
+} & ServiceNavBarOption) => {
+ const colors = useColors()
+
+ const animatedStyles = useAnimatedStyle(() => {
+ return {
+ transform: [
+ {
+ scale: 1,
+ },
+ ],
+ }
+ })
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
+
+type NavServiceBarProps = {
+ navBarOptions: Array
+ selectedValue: string
+ onItemSelected: (value: string) => void
+ onItemLongPress: (value: string) => void
+ hitSlop?: Insets
+} & TouchableOpacityBoxProps
+
+const NavServiceNavBar = ({
+ navBarOptions,
+ selectedValue,
+ onItemSelected,
+ onItemLongPress,
+ ...containerProps
+}: NavServiceBarProps) => {
+ const hitSlop = useVerticalHitSlop('6')
+ const [itemRects, setItemRects] = useState>()
+
+ const offset = useSharedValue(null)
+
+ const handleLayout = useCallback(
+ (value: string) => (e: LayoutChangeEvent) => {
+ e.persist()
+
+ setItemRects((x) => ({ ...x, [value]: e.nativeEvent.layout }))
+ },
+ [],
+ )
+
+ const handlePress = useCallback(
+ (value: string) => () => {
+ onItemSelected(value)
+ },
+ [onItemSelected],
+ )
+
+ const handleLongPress = useCallback(
+ (value: string) => () => {
+ onItemLongPress(value)
+ },
+ [onItemLongPress],
+ )
+
+ useEffect(() => {
+ const nextOffset = itemRects?.[selectedValue]?.x || 0
+
+ if (offset.value === null) {
+ // Don't animate on first position update
+ offset.value = nextOffset
+ return
+ }
+
+ offset.value = withSpring(nextOffset, { mass: 0.5 })
+ }, [itemRects, offset, selectedValue])
+
+ const items = useMemo(() => {
+ return navBarOptions.map((o) => (
+
+ ))
+ }, [
+ handleLayout,
+ handleLongPress,
+ handlePress,
+ hitSlop,
+ navBarOptions,
+ selectedValue,
+ ])
+
+ return (
+
+
+ {items}
+
+
+ )
+}
+
+export default memo(NavServiceNavBar)
diff --git a/src/components/ServiceSheetPage.tsx b/src/components/ServiceSheetPage.tsx
new file mode 100644
index 000000000..1462a5844
--- /dev/null
+++ b/src/components/ServiceSheetPage.tsx
@@ -0,0 +1,166 @@
+import React, { FC, useCallback, useMemo } from 'react'
+import { SvgProps } from 'react-native-svg'
+import {
+ BottomTabBarProps,
+ createBottomTabNavigator,
+} from '@react-navigation/bottom-tabs'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { Color } from '@config/theme/theme'
+import Box from '@components/Box'
+import useEnrichedTransactions from '@hooks/useEnrichedTransactions'
+import useHaptic from '@hooks/useHaptic'
+import { useColors } from '@config/theme/themeHooks'
+import ServiceNavBar from './ServiceNavBar'
+
+const Tab = createBottomTabNavigator()
+
+export type ServiceNavBarOption = {
+ name: string
+ component: React.FC
+ Icon: FC
+ iconProps?: SvgProps
+}
+
+export type ServiceSheetProps = {
+ options: ServiceNavBarOption[]
+}
+
+function CustomTabBar({
+ state,
+ navigation,
+ options,
+}: BottomTabBarProps & {
+ options: ServiceNavBarOption[]
+}) {
+ const { hasNewTransactions, resetNewTransactions } = useEnrichedTransactions()
+ const { triggerImpact } = useHaptic()
+ const { bottom } = useSafeAreaInsets()
+
+ const tabData = useMemo((): Array<{
+ value: string
+ Icon: FC
+ iconColor: Color
+ }> => {
+ return options.map((option) => {
+ return {
+ value: option.name,
+ Icon: option.Icon,
+ iconColor: 'primaryText',
+ iconProps: option.iconProps,
+ }
+ })
+ }, [options])
+
+ const selectedValue = tabData[state.index].value
+
+ const onPress = useCallback(
+ (type: string) => {
+ triggerImpact('light')
+ const index = tabData.findIndex((item) => item.value === type)
+ const isSelected = selectedValue === type
+ const event = navigation.emit({
+ type: 'tabPress',
+ target: state.routes[index || 0].key,
+ canPreventDefault: true,
+ })
+
+ // Check if activty tab is selected and has new transactions
+ if (selectedValue === 'activity' && hasNewTransactions) {
+ resetNewTransactions()
+ }
+
+ if (!isSelected && !event.defaultPrevented) {
+ // The `merge: true` option makes sure that the params inside the tab screen are preserved
+ navigation.navigate({
+ name: state.routes[index || 0].name,
+ merge: true,
+ params: undefined,
+ })
+ }
+ },
+ [
+ hasNewTransactions,
+ navigation,
+ resetNewTransactions,
+ selectedValue,
+ state.routes,
+ tabData,
+ triggerImpact,
+ ],
+ )
+
+ const onLongPress = useCallback(
+ (type: string) => {
+ const index = tabData.findIndex((item) => item.value === type)
+
+ navigation.emit({
+ type: 'tabLongPress',
+ target: state.routes[index || 0].key,
+ })
+ },
+ [navigation, state.routes, tabData],
+ )
+
+ if (options?.length <= 1) {
+ return null
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
+const ServiceSheetPage = ({ options }: ServiceSheetProps) => {
+ const colors = useColors()
+
+ return (
+
+ (
+
+ )}
+ screenOptions={{
+ headerShown: false,
+ lazy: true,
+ }}
+ sceneContainerStyle={{
+ height: '100%',
+ backgroundColor: colors.primaryBackground,
+ }}
+ >
+ {options.map((option) => (
+
+ ))}
+
+
+ )
+}
+
+const ServiceSheetPageWrapper = ({ options }: ServiceSheetProps) => {
+ return
+}
+
+export default ServiceSheetPageWrapper
diff --git a/src/components/SideDrawer.tsx b/src/components/SideDrawer.tsx
new file mode 100644
index 000000000..7001b817c
--- /dev/null
+++ b/src/components/SideDrawer.tsx
@@ -0,0 +1,89 @@
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ FadeInLeft,
+ useAnimatedStyle,
+ withTiming,
+} from 'react-native-reanimated'
+import { ww } from '@utils/layout'
+import TouchableOpacityBox from './TouchableOpacityBox'
+import { Box, ReAnimatedBox, SafeAreaBox, Text } from '.'
+import MenuButton from './MenuButton'
+
+type SideDrawerProps = {
+ isExpanded: boolean
+ onRoute: (route: string) => void
+ onClose: () => void
+}
+
+const SideDrawer = ({ isExpanded, onRoute, onClose }: SideDrawerProps) => {
+ const { t } = useTranslation()
+
+ const routes: { title: string; value: string }[] = useMemo(
+ () =>
+ Array.from(
+ t('sideDrawer.routes', {
+ returnObjects: true,
+ }),
+ ),
+ [t],
+ )
+
+ const animatedStyles = useAnimatedStyle(() => {
+ if (isExpanded) {
+ return {
+ opacity: withTiming(1),
+ }
+ }
+ return {
+ opacity: withTiming(0),
+ }
+ }, [isExpanded])
+
+ const onRoutePressed = useCallback(
+ (route: string) => () => {
+ onRoute(route)
+ },
+ [onRoute],
+ )
+
+ return (
+
+
+
+
+
+
+ {isExpanded &&
+ routes.map((route: { title: string; value: string }, index) => {
+ return (
+
+
+
+ {route.title}
+
+
+
+ )
+ })}
+
+
+
+ )
+}
+
+export default SideDrawer
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 5848f508a..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 = {
@@ -15,14 +16,14 @@ type Props = {
} & BoxProps
const SubmitButton = ({
- color = 'blueBright500',
+ color = 'primaryBackground',
onSubmit,
title,
disabled = false,
- backgroundColor = 'secondaryIcon',
+ backgroundColor = 'primaryText',
...boxProps
}: Props) => {
- const { surfaceSecondary, secondaryText, ...rest } = useColors()
+ const { secondaryText, ...rest } = useColors()
const colorActual = rest[color as keyof typeof rest]
const backgroundActual = rest[backgroundColor as keyof typeof rest]
const icon = useMemo(
@@ -37,20 +38,21 @@ const SubmitButton = ({
color: disabled ? secondaryText : colorActual,
fontSize: 19,
paddingLeft: 30,
+ fontWeight: 600,
},
railStyles: {
- backgroundColor: surfaceSecondary,
- borderColor: surfaceSecondary,
+ backgroundColor: rest['bg.tertiary'],
+ borderColor: rest['bg.tertiary'],
paddingLeft: 8,
},
}),
- [colorActual, disabled, secondaryText, surfaceSecondary],
+ [colorActual, disabled, secondaryText, rest],
)
return (
}
titleMaxFontScale={1}
thumbIconBackgroundColor={backgroundActual}
thumbIconBorderColor={colorActual}
@@ -69,8 +71,8 @@ const SubmitButton = ({
thumbIconComponent={icon}
disableResetOnTap
disabled={disabled}
- disabledRailBackgroundColor={surfaceSecondary}
- disabledThumbIconBackgroundColor={surfaceSecondary}
+ disabledRailBackgroundColor={rest['bg.tertiary']}
+ disabledThumbIconBackgroundColor={rest['bg.tertiary']}
disabledThumbIconBorderColor={secondaryText}
/>
diff --git a/src/components/Surface.tsx b/src/components/Surface.tsx
index 216c46129..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 & {
@@ -12,7 +12,7 @@ type Props = BoxProps & {
}
const Surface = ({
- backgroundColor = 'surface',
+ backgroundColor = 'cardBackground',
children,
style,
...boxProps
@@ -31,7 +31,7 @@ const Surface = ({
return (
{
- const hitSlop = useVerticalHitSlop('l')
+ const hitSlop = useVerticalHitSlop('6')
const [itemRects, setItemRects] = useState>()
const offset = useSharedValue(null)
const { triggerImpact } = useHaptic()
@@ -190,7 +190,7 @@ const TabBar = ({
return (
-
+
{items}
{hasIndicator && (
@@ -204,7 +204,9 @@ const TabBar = ({
/>
)}
- {hasDivider && }
+ {hasDivider && (
+
+ )}
)
}
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 5167f3c08..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, theme, 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, {
@@ -49,8 +53,8 @@ const TI = forwardRef(
TrailingIcon,
onTrailingIconPress,
TrailingIconOptions = {
- paddingVertical: 'm',
- paddingHorizontal: 's',
+ paddingVertical: '4',
+ paddingHorizontal: '2',
},
...rest
}: Props,
@@ -64,7 +68,7 @@ const TI = forwardRef(
const findColor = () => {
if (placeholderTextColor) return colors[placeholderTextColor]
- return colors[theme.inputVariants.regular.color as Color]
+ return colors[darkTheme.inputVariants.regular.color as Color]
}
const color = findColor()
@@ -89,8 +93,8 @@ const TI = forwardRef(
{floatingLabel && (
{floatingLabel}
@@ -98,7 +102,7 @@ const TI = forwardRef(
)}
{optional && (
-
+
)}
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 9c1582c45..dcdb625cb 100644
--- a/src/components/TextTransform.tsx
+++ b/src/components/TextTransform.tsx
@@ -1,24 +1,27 @@
-/* eslint-disable react/jsx-props-no-spreading */
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-nocheck
+
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) => ({
b: ,
- errorText: ,
+ errorText: ,
primaryText: ,
secondaryText: ,
- havelockBlue: ,
- jazzberryJam: ,
- red500: ,
- greenBright500: ,
- blueBright500: ,
- caribbeanGreen: ,
+ 'blue.500': ,
+ 'pink.500': ,
+ 'error.500': ,
+ 'green.light-500': ,
+ 'blue.light-500': ,
+ 'green.400': ,
+ quaternary: ,
codeHighlight: (
mint?: PublicKey
} & BoxProps
@@ -36,13 +35,12 @@ const TokenButton = ({
address,
title,
subtitle,
- showBubbleArrow,
innerBoxProps,
mint,
backgroundColor: backgroundColorProps,
...boxProps
}: Props) => {
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
const colors = useColors()
const { triggerImpact } = useHaptic()
@@ -66,46 +64,33 @@ const TokenButton = ({
>
-
+
{title}
{!!subtitle && (
-
+
{subtitle}
)}
- {showBubbleArrow && (
-
-
-
- )}
)
}
-const styles = StyleSheet.create({
- rotatedBox: {
- height: 18,
- width: 18,
- margin: -9,
- transform: [{ rotate: '45deg' }],
- },
-})
-
export default memo(TokenButton)
diff --git a/src/components/TokenIcon.tsx b/src/components/TokenIcon.tsx
index bb562664e..c0228e32b 100644
--- a/src/components/TokenIcon.tsx
+++ b/src/components/TokenIcon.tsx
@@ -22,10 +22,10 @@ const TokenIcon = ({ size = 40, img }: Props) => {
return (
)
}
diff --git a/src/components/TokenPill.tsx b/src/components/TokenPill.tsx
index ff73d0642..32be579d3 100644
--- a/src/components/TokenPill.tsx
+++ b/src/components/TokenPill.tsx
@@ -3,11 +3,11 @@ import Text from '@components/Text'
import TokenIcon from '@components/TokenIcon'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { PublicKey } from '@solana/web3.js'
-import { useCreateOpacity } from '@theme/themeHooks'
+import { useColors, useCreateOpacity } from '@config/theme/themeHooks'
import React, { memo, useCallback } from 'react'
import { Pressable, ViewStyle } from 'react-native'
-import { Color } from '@theme/theme'
-import CarotDown from '../assets/images/carotDownFull.svg'
+import { Color } from '@config/theme/theme'
+import CarotDown from '../assets/svgs/carotDownFull.svg'
export const TokenPill = memo(
({
@@ -16,8 +16,9 @@ export const TokenPill = memo(
isActive = false,
isDisabled = false,
onPress,
- activeColor = 'black',
- inactiveColor = 'secondary',
+ activeColor = 'secondaryBackground',
+ inactiveColor = 'primaryBackground',
+ hasTicker = true,
...rest
}: {
mint: PublicKey
@@ -28,8 +29,10 @@ export const TokenPill = memo(
style?: ViewStyle | undefined
activeColor?: Color
inactiveColor?: Color
+ hasTicker?: boolean
}) => {
const { symbol, json } = useMetaplexMetadata(mint)
+ const colors = useColors()
const { backgroundStyle: generateBackgroundStyle } = useCreateOpacity()
const getBackgroundColorStylePill = useCallback(
@@ -43,10 +46,10 @@ export const TokenPill = memo(
disabled: boolean
}) => {
if (disabled) {
- return generateBackgroundStyle('surfaceSecondary', 0.5)
+ return generateBackgroundStyle('bg.tertiary', 0.5)
}
if (pressed) {
- return generateBackgroundStyle(activeColor || 'surfaceSecondary', 1.0)
+ return generateBackgroundStyle(activeColor || 'bg.tertiary', 1.0)
}
if (active) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -77,38 +80,40 @@ export const TokenPill = memo(
rest.style ? rest.style : {},
]}
height={45}
- borderRadius="round"
+ borderRadius="full"
flexDirection="row"
alignItems="center"
- shadowColor="black"
+ shadowColor="base.black"
shadowOpacity={0.2}
shadowOffset={{ width: 0, height: 3 }}
shadowRadius={3}
- padding="s"
- paddingRight="m"
+ padding="2"
+ paddingRight="4"
>
-
- {symbol}
-
+ {hasTicker && (
+
+ {symbol}
+
+ )}
{hasCarot && (
-
+
)}
diff --git a/src/components/TokenSelector.tsx b/src/components/TokenSelector.tsx
index 73323464b..0dce6b465 100644
--- a/src/components/TokenSelector.tsx
+++ b/src/components/TokenSelector.tsx
@@ -1,29 +1,28 @@
import TokenIcon from '@components/TokenIcon'
-import {
+import BottomSheet, {
BottomSheetBackdrop,
BottomSheetFlatList,
- BottomSheetModal,
BottomSheetModalProvider,
} from '@gorhom/bottom-sheet'
-import useBackHandler from '@hooks/useBackHandler'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
-import { BoxProps } from '@shopify/restyle'
+import { BoxProps, ThemeProvider } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
-import { useColors, useOpacity } from '@theme/themeHooks'
+import { Theme, lightTheme } from '@config/theme/theme'
+import { useSpacing } from '@config/theme/themeHooks'
import React, {
- ReactNode,
Ref,
forwardRef,
memo,
useCallback,
useImperativeHandle,
- useMemo,
useRef,
} from 'react'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { Portal } from '@gorhom/portal'
+import { useTranslation } from 'react-i18next'
import Box from './Box'
-import ListItem, { LIST_ITEM_HEIGHT } from './ListItem'
+import ListItem from './ListItem'
+import HeliumBottomSheet from './HeliumBottomSheet'
+import { SafeAreaBox, Text } from '.'
export type TokenListItem = {
mint: PublicKey
@@ -34,11 +33,12 @@ const ProvidedListItem = ({
mint,
onPress,
selected,
+ ...rest
}: {
mint: PublicKey
onPress: () => void
selected: boolean
-}) => {
+} & BoxProps) => {
const { symbol, json } = useMetaplexMetadata(mint)
return (
: undefined}
onPress={onPress}
selected={selected}
- paddingStart="l"
+ paddingStart="6"
hasDivider
+ {...rest}
/>
)
}
@@ -56,42 +57,47 @@ export type TokenSelectorRef = {
showTokens: () => void
}
type Props = {
- children: ReactNode
onTokenSelected: (mint: PublicKey) => void
tokenData: TokenListItem[]
} & BoxProps
const TokenSelector = forwardRef(
- (
- { children, onTokenSelected, tokenData, ...boxProps }: Props,
- ref: Ref,
- ) => {
+ ({ onTokenSelected, tokenData }: Props, ref: Ref) => {
useImperativeHandle(ref, () => ({ showTokens }))
- const { bottom } = useSafeAreaInsets()
- const bottomSheetModalRef = useRef(null)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
- const { secondaryText } = useColors()
+ const spacing = useSpacing()
+ const bottomSheetModalRef = useRef(null)
+ const { t } = useTranslation()
const showTokens = useCallback(() => {
- bottomSheetModalRef.current?.present()
- setIsShowing(true)
- }, [setIsShowing])
+ bottomSheetModalRef.current?.expand()
+ }, [])
const renderBackdrop = useCallback(
(props) => (
+ >
+
+
+ {t('tokenSelector.title')}
+
+
+
),
- [],
+ [t],
)
const handleTokenPress = useCallback(
(token: PublicKey) => {
- bottomSheetModalRef.current?.dismiss()
+ bottomSheetModalRef.current?.close()
onTokenSelected(token)
},
[onTokenSelected],
@@ -102,51 +108,54 @@ const TokenSelector = forwardRef(
}, [])
const renderFlatlistItem = useCallback(
- ({ item }: { item: TokenListItem; index: number }) => {
+ ({ item, index }: { item: TokenListItem; index: number }) => {
+ const borderTopStartRadius = index === 0 ? '2xl' : 'none'
+ const borderTopEndRadius = index === 0 ? '2xl' : 'none'
+ const borderBottomStartRadius =
+ index === tokenData.length - 1 ? '2xl' : 'none'
+ const borderBottomEndRadius =
+ index === tokenData.length - 1 ? '2xl' : 'none'
+
return (
handleTokenPress(item.mint)}
mint={item.mint}
+ borderTopStartRadius={borderTopStartRadius}
+ borderTopEndRadius={borderTopEndRadius}
+ borderBottomStartRadius={borderBottomStartRadius}
+ borderBottomEndRadius={borderBottomEndRadius}
/>
)
},
- [handleTokenPress],
+ [handleTokenPress, tokenData],
)
- const snapPoints = useMemo(
- () => [(tokenData.length + 2) * LIST_ITEM_HEIGHT + bottom],
- [bottom, tokenData.length],
- )
-
- const handleIndicatorStyle = useMemo(() => {
- return {
- backgroundColor: secondaryText,
- }
- }, [secondaryText])
-
return (
-
-
-
-
-
- {children}
-
-
+
+
+
+
+
+
+
+
+
+
+
)
},
)
diff --git a/src/components/TotalFiatBalance.tsx b/src/components/TotalFiatBalance.tsx
new file mode 100644
index 000000000..905df6289
--- /dev/null
+++ b/src/components/TotalFiatBalance.tsx
@@ -0,0 +1,153 @@
+import React, { memo, useEffect, useMemo, useState } from 'react'
+import AnimatedNumbers from 'react-native-animated-numbers'
+import { useTextVariants } from '@config/theme/themeHooks'
+import { Easing } from 'react-native-reanimated'
+import { useBalance } from '@utils/Balance'
+import { useTheme } from '@shopify/restyle'
+import Box from './Box'
+import Text from './Text'
+
+const TotalFiatBalance = () => {
+ const { total: amount } = useBalance()
+ const { colors } = useTheme()
+
+ const textVariants = useTextVariants()
+ const integral = useMemo(() => Math.floor(amount || 0), [amount])
+ const [realAmount, setAmount] = useState(amount || 0)
+
+ const firstFractional = useMemo(() => {
+ if (realAmount === undefined) return 0
+ const decimal = realAmount - integral
+ const fraction = decimal.toString().split('.')[1]
+ // Fraction with max length of decimals
+ const fractionWithMaxDecimals = fraction?.slice(0, 1)
+ return fraction ? Number(fractionWithMaxDecimals) : 0
+ }, [realAmount, integral])
+
+ const secondFractional = useMemo(() => {
+ if (realAmount === undefined) return 0
+ const decimal = realAmount - integral
+ const fraction = decimal.toString().split('.')[1]
+ // Fraction with max length of decimals
+ const fractionWithMaxDecimals = fraction?.slice(1, 2)
+ return fraction ? Number(fractionWithMaxDecimals) : 0
+ }, [realAmount, integral])
+
+ useEffect(() => {
+ if (!amount) return
+
+ setTimeout(() => {
+ setAmount(amount)
+ }, 3000)
+ }, [amount])
+
+ return (
+
+
+
+ $
+
+
+
+ .
+
+
+
+
+ {/*
+ TODO: Bring this back once we are tracking balances on the wallet api
+
+
+
+ */}
+
+ )
+}
+
+// TODO: Bring this back once we are tracking balances on the wallet api
+// const BalanceChange = ({ change }: { change: number }) => {
+// return (
+//
+// {`$${change.toFixed(2).toLocaleString()}`}
+//
+// )
+// }
+
+// TODO: Bring this back once we are tracking balances on the wallet api
+// const PercentageContainer = ({
+// percentage,
+// type,
+// }: {
+// percentage: number
+// type: 'up' | 'down' | 'neutral'
+// }) => {
+// const backgroundColor = useMemo(() => {
+// switch (type) {
+// case 'up':
+// return 'green.light-500'
+// case 'down':
+// return 'error.500'
+// case 'neutral':
+// return 'fg.quinary-400'
+// }
+// }, [type])
+
+// return (
+//
+//
+// {`+${percentage.toFixed(2)}%`}
+//
+//
+// )
+// }
+
+export default memo(TotalFiatBalance)
diff --git a/src/components/TouchableContainer.tsx b/src/components/TouchableContainer.tsx
index 02e795b64..fa9fea27d 100644
--- a/src/components/TouchableContainer.tsx
+++ b/src/components/TouchableContainer.tsx
@@ -1,7 +1,7 @@
import useHaptic from '@hooks/useHaptic'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
-import { useCreateOpacity } from '@theme/themeHooks'
+import { Theme } from '@config/theme/theme'
+import { useCreateOpacity } from '@config/theme/themeHooks'
import React, { useCallback } from 'react'
import {
GestureResponderEvent,
@@ -31,8 +31,8 @@ const TouchableContainer = ({
pressableStyles,
onLayout,
hitSlop,
- backgroundColor = 'surfaceSecondary',
- backgroundColorPressed = 'black500',
+ backgroundColor = 'cardBackground',
+ backgroundColorPressed = 'gray.200',
...boxProps
}: ButtonPressAnimationProps & {
backgroundColorPressed?: BoxProps['backgroundColor']
diff --git a/src/components/TouchableHighlightBox.tsx b/src/components/TouchableHighlightBox.tsx
index 7f17a997d..29a48fdce 100644
--- a/src/components/TouchableHighlightBox.tsx
+++ b/src/components/TouchableHighlightBox.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import { createBox } from '@shopify/restyle'
import { TouchableHighlight, TouchableHighlightProps } from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import WithDebounce from './WithDebounce'
const TouchableHighlightBox = createBox<
diff --git a/src/components/TouchableOpacityBox.tsx b/src/components/TouchableOpacityBox.tsx
index b08a43d30..053bb4bdb 100644
--- a/src/components/TouchableOpacityBox.tsx
+++ b/src/components/TouchableOpacityBox.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import { createBox } from '@shopify/restyle'
import { TouchableOpacity, TouchableOpacityProps } from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import WithDebounce from './WithDebounce'
const TouchableOpacityBox = createBox<
diff --git a/src/components/TouchableWithoutFeedbackBox.tsx b/src/components/TouchableWithoutFeedbackBox.tsx
index e0e0188cc..6e5510465 100644
--- a/src/components/TouchableWithoutFeedbackBox.tsx
+++ b/src/components/TouchableWithoutFeedbackBox.tsx
@@ -4,7 +4,7 @@ import {
TouchableWithoutFeedback,
TouchableWithoutFeedbackProps,
} from 'react-native'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import WithDebounce from './WithDebounce'
const TouchableWithoutFeedbackBox = createBox<
diff --git a/src/components/TreasuryWarningScreen.tsx b/src/components/TreasuryWarningScreen.tsx
index a191d1979..9c1d30adb 100644
--- a/src/components/TreasuryWarningScreen.tsx
+++ b/src/components/TreasuryWarningScreen.tsx
@@ -6,8 +6,8 @@ import React, {
useMemo,
useState,
} from 'react'
-import { ScrollView, View } from 'react-native'
-import InfoWarning from '@assets/images/warning.svg'
+import { View } from 'react-native'
+import InfoWarning from '@assets/svgs/warning.svg'
import { useTranslation } from 'react-i18next'
import Animated, {
runOnJS,
@@ -15,8 +15,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'
@@ -24,6 +24,7 @@ import {
parseSolanaStatus,
useGetSolanaStatusQuery,
} from '../store/slices/solanaStatusApi'
+import ScrollBox from './ScrollBox'
const TreausuryWarningScreen = ({ children }: { children: ReactNode }) => {
const { t } = useTranslation()
@@ -75,7 +76,7 @@ const TreausuryWarningScreen = ({ children }: { children: ReactNode }) => {
{children}
{!animationComplete && (
- {
backgroundColor="primaryBackground"
flex={1}
justifyContent="center"
- paddingHorizontal="xl"
+ paddingHorizontal="8"
height="100%"
>
-
+
{
{t('swapsScreen.treasurySwapWarningBody')}
-
+
)}
diff --git a/src/components/WalletAlertBanner.tsx b/src/components/WalletAlertBanner.tsx
new file mode 100644
index 000000000..40d2143f5
--- /dev/null
+++ b/src/components/WalletAlertBanner.tsx
@@ -0,0 +1,73 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useOwnedAmount } from '@helium/helium-react-hooks'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+import { NATIVE_MINT } from '@solana/spl-token'
+import { MIN_BALANCE_THRESHOLD } from '@utils/constants'
+import { runOnJS, useAnimatedStyle, withTiming } from 'react-native-reanimated'
+import useLayoutHeight from '@hooks/useLayoutHeight'
+import { Box, ReAnimatedBox, Text } from '.'
+
+const WalletAlertBanner = () => {
+ const { t } = useTranslation()
+ const wallet = useCurrentWallet()
+ const { amount } = useOwnedAmount(wallet, NATIVE_MINT)
+ const [isExpanded, setIsExpanded] = useState(false)
+ const [height, setHeight] = useLayoutHeight()
+ const [animationComplete, setAnimationComplete] = useState(false)
+
+ useEffect(() => {
+ if ((amount || 0) < MIN_BALANCE_THRESHOLD) {
+ setIsExpanded(true)
+ }
+ }, [amount])
+
+ const body = useMemo(() => {
+ if ((amount || 0) < MIN_BALANCE_THRESHOLD) {
+ return t('walletAlertBanner.insufficentSol')
+ }
+ }, [amount, t])
+
+ const onAnimationComplete = useCallback((isFinished) => {
+ if (isFinished) {
+ setAnimationComplete(true)
+ }
+ }, [])
+
+ const animatedStyles = useAnimatedStyle(() => {
+ if (isExpanded) {
+ return {
+ height: withTiming(
+ height > 0 && animationComplete ? height : 80,
+ undefined,
+ runOnJS(onAnimationComplete),
+ ),
+ opacity: withTiming(1),
+ }
+ }
+
+ return {
+ height: withTiming(0),
+ opacity: withTiming(0),
+ }
+ }, [isExpanded, height, animationComplete])
+
+ if (!body) return null
+
+ return (
+
+
+
+ {body}
+
+
+
+ )
+}
+
+export default WalletAlertBanner
diff --git a/src/components/WarningBanner.tsx b/src/components/WarningBanner.tsx
index 1b3cf0b56..5e5efcb93 100644
--- a/src/components/WarningBanner.tsx
+++ b/src/components/WarningBanner.tsx
@@ -7,10 +7,10 @@ import {
initialWindowMetrics,
} from 'react-native-safe-area-context'
import { useDispatch, useSelector } from 'react-redux'
-import InfoWarning from '@assets/images/warning.svg'
-import CloseCircle from '@assets/images/closeCircleFilled.svg'
+import InfoWarning from '@assets/svgs/warning.svg'
+import CloseCircle from '@assets/svgs/closeCircleFilled.svg'
import { BoxProps } from '@shopify/restyle'
-import { Theme } from '@theme/theme'
+import { Theme } from '@config/theme/theme'
import { LayoutChangeEvent } from 'react-native'
import useSolanaHealth from '@hooks/useSolanaHealth'
import { RootState } from '../store/rootReducer'
@@ -68,15 +68,15 @@ const Banner = ({ type, onLayout, ...rest }: BannerProps) => {
return (
{
- 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 88%
rename from src/locales/en.ts
rename to src/config/locales/en.ts
index d84d72352..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.',
@@ -121,7 +134,7 @@ export default {
recoveryPhrase: 'Secret Phrase',
keyImport: 'Private Key',
subTitle:
- 'To import your existing Helium wallet, enter its 12 or 24 word security key.',
+ 'To import your existing Helium wallet, enter its 12 or 24 word security key.',
title: 'Import\nWallet',
wordEntry: {
changeWordAmount: 'Change to a {{totalWords}}-word recovery phrase',
@@ -195,8 +208,7 @@ export default {
},
accountsScreen: {
activity: 'Activity',
- allFilterFooter:
- "You've reached the end of your activity.\nSelect a different filter to view more.",
+ allFilterFooter: "You've reached the end of your activity.",
filter: 'Filter',
filterTransactions: 'Filter Transactions',
filterTypes: {
@@ -233,8 +245,8 @@ export default {
collectablesScreen: {
title: 'Collectables',
metadata: 'Metadata',
- transfer: 'Transfer Hotspot',
- transferComplete: 'Hotspot Transferred!',
+ transfer: 'Transfer',
+ transferComplete: 'Asset Transferred!',
returnToCollectables: 'Return to Collectables',
transferFee: 'Fee {{ amount }} SOL ',
transferingNftTitle: 'Transferring NFT...',
@@ -263,7 +275,8 @@ export default {
},
nfts: {
title: 'NFTs',
- nftDetialTitle: 'NFT Detail',
+ nftDetailTitle: 'NFT Detail',
+ setAsAvatar: 'Set as Avatar',
},
hotspots: {
title: 'Hotspots',
@@ -310,7 +323,8 @@ export default {
},
},
activityScreen: {
- title: 'My Activity',
+ title: 'Activity',
+ subtitle: 'View your blockchain history.',
transactionSuccessful: 'Transaction Successful',
transactionFailed: 'Transaction Failed',
viewOnExplorer: 'View on Explorer',
@@ -461,7 +475,8 @@ export default {
swapsScreen: {
priceImpact:
'Price impact more than {{percent}}%. Try swapping a smaller amount.',
- title: 'Swap my Tokens',
+ title: 'Swap',
+ subtitle: 'Swap your tokens for others',
swapTokens: 'Swap Tokens',
youPay: 'You Pay',
youReceive: 'You Receive',
@@ -929,7 +944,7 @@ export default {
addRecipient: '+ Add Recipient',
backToAccounts: 'Back to Wallets',
enterAddress: 'Enter Address',
- enterAmount: 'Enter {{ticker}} Amount',
+ enterAmount: 'Enter Amount',
enterMemo: 'Enter Memo (Optional)',
fee: '+{{value}} Fee',
insufficientFunds: 'Insufficient {{token}}',
@@ -952,6 +967,7 @@ export default {
selectContact: 'Select Contact',
selfPay: 'Self Pay',
send: 'Send',
+ sendTokensToAnyAddress: 'Send tokens to any address on the Solana Network.',
sendButton: 'Swipe to Send {{ticker}}',
senderAccount: 'Sender Wallet',
sending: 'Sending...',
@@ -967,6 +983,7 @@ export default {
submitSuccess: 'Transaction\nSubmitted',
title: 'Send {{ticker}}',
total: 'Total',
+ to: 'To',
totalRecipients: '{{count}} Recipient',
totalRecipients_one: '{{count}} Recipient',
totalRecipients_other: '{{count}} Recipients',
@@ -1021,6 +1038,9 @@ export default {
},
},
settings: {
+ system: 'System',
+ light: 'Light',
+ dark: 'Dark',
confirmSignout: {
forgotAlert: {
body: 'Would you like to reveal your wallets words?',
@@ -1034,14 +1054,14 @@ export default {
alertTitle: 'Are you sure?',
done: 'Done',
subtitle:
- 'Do not share your private key!\n\nIf someone has your private key they will have full control of your wallet! Do not enter this into any websites. Any individual asking for this key is likely a scammer.',
+ 'Do not share your private key!\n\nIf someone has your private key they will have full control of your wallet! Do not enter this into any websites. Any individual asking for this key is likely a scammer.',
tap: 'Tap to reveal your private key',
title: 'Your Private Key',
},
revealWords: {
next: 'I have written these down',
subtitle:
- 'Never give these words to anyone, or enter them into any website. Any person or website asking for these words is likely a scammer. It is crucial you write all of these\n{{numWords}} words down, in order, and keep them safe.\n\nHelium cannot recover these words.',
+ 'Never give these words to anyone, or enter them into any website. Any person or website asking for these words is likely a scammer. It is crucial you write all of these\n{{numWords}} words down, in order, and keep them safe.\n\nHelium cannot recover these words.',
title: 'Your {{numWords}} Word Password',
warning: 'Helium cannot recover these words',
},
@@ -1274,7 +1294,7 @@ export default {
title: 'Vote Power',
},
{
- body: 'Get your voice heard.\n\nVote on Active Votes\nManage your locked positions\nOr browse past HIPs.',
+ body: 'Get your voice heard.\n\nVote on Active Votes\nManage your locked positions\nOr browse past HIPs.',
title: 'Ready to Vote?',
},
],
@@ -1464,4 +1484,177 @@ export default {
relinquishVotes: 'Relinquish votes failed, please try again.',
},
},
+ sideDrawer: {
+ routes: [
+ {
+ title: 'Wallet',
+ value: 'wallet',
+ },
+ {
+ title: 'Governance',
+ value: 'governance',
+ },
+ {
+ title: 'Hotspots',
+ value: 'hotspots',
+ },
+ {
+ title: 'Browser',
+ value: 'browser',
+ },
+ {
+ title: 'Notifications',
+ value: 'notifications',
+ },
+ {
+ title: 'Settings',
+ value: 'settings',
+ },
+ ],
+ },
+ walletAlertBanner: {
+ insufficentSol:
+ 'Insufficient SOL to pay for fees. Please add more SOL to your wallet.',
+ tokenPrice:
+ 'We are currently experiencing issues fetching token prices. Please try again later.',
+ },
+ accountsService: {
+ title: 'Your Wallets',
+ switchingAccounts: 'Switching accounts',
+ addingSubAccount: 'Adding Sub Account',
+ pleaseBePatient: 'Please be patient. This may take a moment.',
+ },
+ receivePage: {
+ title: 'Receive',
+ subtitle: 'Share your QR or address to request tokens.',
+ shareQr: 'Share QR',
+ copyAddress: 'Copy Address',
+ },
+ tokenSelector: {
+ title: 'Select a currency',
+ },
+ addressBookSelector: {
+ title: 'Select a contact',
+ },
+ blurActionSheet: {
+ selectAnOption: 'Select an option',
+ },
+ 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 88%
rename from src/storage/AccountStorageProvider.tsx
rename to src/config/storage/AccountStorageProvider.tsx
index 7c0630fb4..415caf048 100644
--- a/src/storage/AccountStorageProvider.tsx
+++ b/src/config/storage/AccountStorageProvider.tsx
@@ -14,15 +14,17 @@ import React, {
} from 'react'
import { useAsync } from 'react-async-hook'
import Config from 'react-native-config'
-import { authSlice } from '../store/slices/authSlice'
-import { useAppDispatch } from '../store/store'
+import { cloneDeep } from 'lodash'
+import { authSlice } from '@store/slices/authSlice'
+import { useAppDispatch } from '@store/store'
import {
accountNetType,
AccountNetTypeOpt,
heliumAddressToSolAddress,
-} from '../utils/accountUtils'
-import makeApiToken from '../utils/makeApiToken'
-import { getSessionKey } from '../utils/walletApiV2'
+ solAddressToHelium,
+} from '@utils/accountUtils'
+import makeApiToken from '@utils/makeApiToken'
+import { getSessionKey } from '@utils/walletApiV2'
import { useAppStorage } from './AppStorageProvider'
import {
CSAccount,
@@ -308,17 +310,24 @@ const useAccountStorageHook = () => {
const editContact = useCallback(
async (oldAddress: string, updatedAccount: CSAccount) => {
- const nextAccount = updatedAccount
+ let nextAccount = cloneDeep(updatedAccount)
+ if (updatedAccount.address === oldAddress) return
+
if (!nextAccount.solanaAddress && nextAccount.address) {
- nextAccount.solanaAddress = heliumAddressToSolAddress(
- nextAccount.address,
+ nextAccount = {
+ ...nextAccount,
+ solanaAddress: heliumAddressToSolAddress(nextAccount.address),
+ }
+ }
+ let filtered: CSAccount[] = contacts
+ if (oldAddress !== updatedAccount.address) {
+ filtered = contacts.filter(
+ (c) =>
+ c.address !== oldAddress &&
+ c.solanaAddress !== heliumAddressToSolAddress(oldAddress),
)
}
- const filtered = contacts.filter(
- (c) =>
- c.address !== oldAddress &&
- c.solanaAddress !== heliumAddressToSolAddress(oldAddress),
- )
+
const nextContacts = [...filtered, nextAccount]
setContacts(nextContacts)
@@ -339,6 +348,35 @@ const useAccountStorageHook = () => {
[contacts],
)
+ const editAvatar = useCallback(
+ async (avatar: string) => {
+ if (!accounts || !currentAccount?.address) return
+
+ const editedAccount: CSAccount = {
+ ...currentAccount,
+ avatar,
+ }
+
+ const editedAccounts = accounts
+ editedAccounts[currentAccount?.address] = editedAccount
+
+ setAccounts(editedAccounts)
+ setCurrentAccount(editedAccount)
+ await updateCloudAccounts(editedAccounts)
+ },
+ [currentAccount, accounts],
+ )
+
+ const getAvatar = useCallback(
+ async (address: string) => {
+ if (!accounts) return
+ const account = accounts[solAddressToHelium(address)]
+
+ return account?.avatar
+ },
+ [accounts],
+ )
+
const updateDefaultAccountAddress = useCallback(
async (address: string | undefined) => {
await setCloudDefaultAccountAddress(address)
@@ -419,6 +457,8 @@ const useAccountStorageHook = () => {
updateDefaultAccountAddress,
upsertAccount,
upsertAccounts,
+ editAvatar,
+ getAvatar,
}
}
@@ -445,6 +485,8 @@ const initialState = {
sortedTestnetAccounts: [],
upsertAccount: async () => undefined,
upsertAccounts: async () => undefined,
+ editAvatar: async () => undefined,
+ getAvatar: async () => undefined,
}
const AccountStorageContext =
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 99%
rename from src/storage/cloudStorage.ts
rename to src/config/storage/cloudStorage.ts
index 012c58aaa..1f823c12e 100644
--- a/src/storage/cloudStorage.ts
+++ b/src/config/storage/cloudStorage.ts
@@ -37,6 +37,8 @@ export type CSAccount = {
proposalIdsSeenByMint?: Record
//
version?: CSAccountVersion
+ // avatar uri
+ avatar?: string
}
export type CSAccountVersion = 'v1'
export type CSAccounts = Record
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/config/theme/theme.ts b/src/config/theme/theme.ts
new file mode 100644
index 000000000..93396c863
--- /dev/null
+++ b/src/config/theme/theme.ts
@@ -0,0 +1,225 @@
+import { createTheme } from '@shopify/restyle'
+
+import darkThemeTokens from '@novalabsxyz/mobile-theme/build/dark-theme.json'
+import lightThemeTokens from '@novalabsxyz/mobile-theme/build/light-theme.json'
+
+const NovaFont = {
+ bold: 'Figtree',
+ boldItalic: 'Figtree',
+ italic: 'Figtree',
+ light: 'Figtree',
+ medium: 'Figtree',
+ mediumItalic: 'Figtree',
+ regular: 'Figtree',
+ semiBold: 'Figtree',
+}
+
+export const breakpoints = {
+ none: 0,
+ xs: 300,
+ sm: 400,
+ md: 640,
+ lg: 960,
+ xl: 1200,
+ xxl: 1440,
+}
+
+export const baseTheme = {
+ borderRadii: { ...lightThemeTokens.borderRadii, '6xl': 40 },
+ breakpoints,
+ Font: NovaFont,
+ inputVariants: {
+ outline: {
+ color: 'primaryText',
+ fontSize: 18,
+ fontFamily: 'Figtree',
+ padding: '4',
+ borderRadius: '4xl',
+ },
+ outlineSuccess: {
+ color: 'blue.500',
+ fontSize: 18,
+ fontFamily: 'Figtree',
+ padding: '4',
+ borderRadius: '4xl',
+ borderWidth: 1,
+ borderColor: 'blue.500',
+ },
+ plain: {
+ color: 'primaryText',
+ fontSize: 18,
+ fontFamily: 'Figtree',
+ padding: '4',
+ backgroundColor: 'inputBackground',
+ },
+ regular: {
+ color: 'primaryText',
+ fontSize: 18,
+ fontFamily: 'Figtree',
+ padding: '4',
+ backgroundColor: 'inputBackground',
+ borderRadius: '4xl',
+ },
+ transparent: {
+ color: 'primaryText',
+ fontSize: 19,
+ padding: '4',
+ backgroundColor: 'transparent',
+ borderRadius: '4xl',
+ },
+ thickBlur: {
+ padding: '4',
+ borderRadius: '4xl',
+ backgroundColor: 'transparent10',
+ },
+ thickDark: {
+ padding: 'm',
+ borderRadius: '4xl',
+ backgroundColor: 'bg.tertiary',
+ },
+ transparentSmall: {
+ color: 'primaryText',
+ fontSize: 16,
+ padding: '2',
+ paddingHorizontal: '4',
+ backgroundColor: 'transparent',
+ },
+ underline: {
+ fontSize: 36,
+ color: 'purple.500',
+ borderBottomColor: 'purple.500',
+ borderBottomWidth: 2,
+ paddingBottom: 'xs',
+ },
+ },
+ cardVariants: {
+ regular: {
+ padding: '4',
+ borderRadius: 'xl',
+ backgroundColor: 'cardBackground',
+ },
+ elevated: {
+ shadowColor: 'cardBackground',
+ borderRadius: 'xl',
+ shadowOffset: {
+ width: 0,
+ height: 9,
+ },
+ shadowOpacity: 0.3,
+ shadowRadius: 6,
+ elevation: 9,
+ },
+ modal: {
+ backgroundColor: 'cardBackground',
+ borderRadius: '4xl',
+ },
+ },
+ spacing: {
+ ...lightThemeTokens.spacing,
+ },
+ textVariants: {
+ ...lightThemeTokens.textVariants,
+ },
+}
+
+const lightColors = lightThemeTokens.colors
+const darkColors = darkThemeTokens.colors
+
+const allSpacing = {
+ ...baseTheme.spacing,
+ // TODO: Add thise spacings to the theme
+ '-24': -96,
+ '-8': -32,
+ '-7': -28,
+ '-0.25': -1,
+ '0.25': 1,
+ '0.5': 2,
+ '0.75': 3,
+ '1': 4,
+ '2.5': 10,
+ '6': 24,
+ '7': 28,
+ '11': 44,
+ '14': 56,
+ '15': 60,
+ '28': 112,
+}
+
+const lightTheme = createTheme({
+ ...baseTheme,
+ spacing: allSpacing,
+ colors: {
+ ...lightColors,
+
+ primaryBackground: lightColors['bg.primary'], // background.bg.primary
+ secondaryBackground: lightColors['bg.secondary'], // background.bg.secondary
+ cardBackground: lightColors['bg.tertiary'], // background.bg.primary // add border around all cards... secondary border
+ primaryText: lightColors['text.primary-900'], // text.primary.900 -> text.primary
+ secondaryText: lightColors['text.secondary-700'], // text.text.secondary.700 -> text.secondary
+ placeholderText: lightColors['text.placeholder'], // text.placeholder
+ // accentText: palette.silver, // text.tertiary, //probably remove
+ inputBackground: lightColors['bg.primary'], // background.bg.primary // add border around all inputs... primary border
+ activeBackground: lightColors['bg.active'], // background.bg.active
+ inactiveIcon: lightColors['fg.disabled'], // foreground.fg.disabled
+ transparent10: '#ffffff1A',
+ transparent: '#00000000',
+ hntBlue: '#2755F8',
+ mobileDarkBlue: '#00273D',
+ mobileBlue: '#009EF8',
+ iotDarkGreen: '#053919',
+ iotGreen: '#26ED75',
+ solanaPurple: '#9945FF',
+ },
+})
+
+const darkTheme = createTheme({
+ ...baseTheme,
+ spacing: allSpacing,
+ colors: {
+ ...darkColors,
+
+ primaryBackground: darkColors['bg.primary'], // background.bg.primary
+ secondaryBackground: darkColors['bg.secondary'], // background.bg.secondary
+ cardBackground: darkColors['bg.tertiary'], // background.bg.primary // add border around all cards... secondary border
+ primaryText: darkColors['text.primary-900'], // text.primary.900 -> text.primary
+ secondaryText: darkColors['text.secondary-700'], // text.text.secondary.700 -> text.secondary
+ placeholderText: darkColors['text.placeholder'], // text.placeholder
+ // accentText: palette.silver, // text.tertiary, //probably remove
+ inputBackground: darkColors['bg.primary'], // background.bg.primary // add border around all inputs... primary border
+ activeBackground: darkColors['bg.active'], // background.bg.active
+ inactiveIcon: darkColors['fg.disabled'], // foreground.fg.disabled
+ transparent10: '#ffffff1A',
+ transparent: '#00000000',
+ hntBlue: '#2755F8',
+ mobileDarkBlue: '#00273D',
+ mobileBlue: '#009EF8',
+ iotDarkGreen: '#053919',
+ iotGreen: '#26ED75',
+ solanaPurple: '#9945FF',
+ },
+})
+
+export type Theme = typeof lightTheme
+export type TextVariant = keyof Theme['textVariants']
+export type TextInputVariant = keyof Theme['inputVariants']
+export type Spacing = keyof Theme['spacing']
+export type Color = keyof Theme['colors']
+export type BorderRadii = keyof Theme['borderRadii']
+export type FontWeight =
+ | '100'
+ | '200'
+ | '300'
+ | '400'
+ | '500'
+ | '600'
+ | '700'
+ | '800'
+ | '900'
+ | 'normal'
+ | 'bold'
+
+export { lightColors, darkColors }
+
+export { NovaFont as Font }
+
+export { lightTheme, darkTheme }
diff --git a/src/theme/themeHooks.ts b/src/config/theme/themeHooks.ts
similarity index 95%
rename from src/theme/themeHooks.ts
rename to src/config/theme/themeHooks.ts
index b17ee4d03..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'
@@ -138,9 +138,9 @@ export const useBreakpoints = () => {
const { breakpoints } = useTheme()
const width = ww
return {
- smallPhone: breakpoints.phone > width,
- largePhone: breakpoints.largePhone <= width,
- phone: breakpoints.phone <= width,
+ smallPhone: breakpoints.sm > width,
+ largePhone: breakpoints.md <= width,
+ phone: breakpoints.sm <= width,
}
}
diff --git a/src/features/StatusPage/StatusBanner.tsx b/src/features/StatusPage/StatusBanner.tsx
index e8f59c9fa..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'
@@ -21,7 +21,7 @@ const onTapStatusBanner = async () => {
const StatusBanner = () => {
const { t } = useTranslation()
const incidents = useStatusPage()
- const hitSlop = useHitSlop('m')
+ const hitSlop = useHitSlop('4')
const { primaryText } = useColors()
const getAlertDescription = useCallback(
@@ -53,7 +53,7 @@ const StatusBanner = () => {
return (
-
-const AccountTokenScreen = () => {
- const { t } = useTranslation()
- const route = useRoute()
- const { currentAccount } = useAccountStorage()
- const [filtersOpen, setFiltersOpen] = useState(false)
- const [topHeaderHeight, setTopHeaderHeight] = useState(0)
- const [listHeight, setListHeight] = useLayoutHeight()
- const [bottomScreenHeaderHeight, setBottomScreenHeaderHeight] =
- useLayoutHeight()
- const [backHeaderHeight, setBackHeaderHeight] = useLayoutHeight()
- const topHeaderRef = useRef(null)
- const headerContainerRef = useRef(null)
- const [topHeaderYPos, setTopHeaderYPos] = useState(0)
- const [headerContainerYPos, setHeaderContainerYPos] = useState(0)
- const listAnimatedPos = useSharedValue(0)
- const { cluster, isDevnet } = useSolana()
- const insets = useSafeAreaInsets()
- const colors = useColors()
- const { showModal } = useModal()
- const [
- onEndReachedCalledDuringMomentum,
- setOnEndReachedCalledDuringMomentum,
- ] = useState(true)
-
- const mintStr = useMemo(() => route.params.mint, [route.params.mint])
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const mint = usePublicKey(mintStr)!
-
- const { json, symbol } = useMetaplexMetadata(mint)
-
- const toggleFiltersOpen = useCallback(
- (open) => () => {
- setFiltersOpen(open)
- },
- [],
- )
-
- const listStyle = useMemo(() => {
- return {
- backgroundColor: colors.primaryBackground,
- }
- }, [colors])
-
- const filterState = useActivityFilter()
-
- const {
- data: activityData,
- requestMore: fetchMoreActivity,
- loading: activityLoading,
- now,
- } = useSolanaActivityList({
- account: currentAccount,
- filter: filterState.filter,
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- mint: mint!,
- })
-
- const handleOnFetchMoreActivity = useCallback(() => {
- if (activityLoading || onEndReachedCalledDuringMomentum) return
-
- fetchMoreActivity()
- setOnEndReachedCalledDuringMomentum(true)
- }, [activityLoading, fetchMoreActivity, onEndReachedCalledDuringMomentum])
-
- const handleOnMomentumScrollBegin = useCallback(() => {
- setOnEndReachedCalledDuringMomentum(false)
- }, [])
-
- const actualHeight = useMemo(() => {
- return WINDOW_HEIGHT - insets.bottom - NavBarHeight
- }, [insets.bottom])
-
- const snapPoints = useMemo(() => {
- if (!topHeaderYPos || !headerContainerYPos) return
- const collapsed = Math.max(
- actualHeight - headerContainerYPos,
- MIN_BOTTOM_BAR_HEIGHT,
- )
- const expanded = actualHeight
- ? actualHeight - insets.top - backHeaderHeight - topHeaderHeight
- : 0
- return [collapsed, expanded]
- }, [
- actualHeight,
- backHeaderHeight,
- headerContainerYPos,
- insets.top,
- topHeaderHeight,
- topHeaderYPos,
- ])
- const wallet = useCurrentWallet()
- const { amount } = useOwnedAmount(wallet, mint)
-
- const canShowList = useMemo(() => snapPoints?.length === 2, [snapPoints])
-
- const topHeaderAnimatedStyle = useAnimatedStyle(() => {
- if (!snapPoints || !canShowList) {
- return { opacity: 0 }
- }
-
- const o =
- (listAnimatedPos.value - insets.top - topHeaderHeight) /
- (snapPoints[1] - snapPoints[0])
-
- return {
- opacity: 1 - o,
- position: 'absolute',
- left: 0,
- right: 0,
- }
- }, [snapPoints, topHeaderHeight, listHeight])
-
- const bottomHeaderAnimatedStyle = useAnimatedStyle(() => {
- if (!snapPoints || !canShowList) {
- return { opacity: 1 }
- }
-
- const expandedPosition = actualHeight - snapPoints[1]
- const diff = listAnimatedPos.value - expandedPosition
- const o = diff / (snapPoints[1] - snapPoints[0])
-
- return {
- opacity: o,
- }
- }, [snapPoints, topHeaderHeight, listHeight])
-
- const { show: showTxnDetail } = useTransactionDetail()
-
- const showTransactionDetail = useCallback(
- (item: Activity) => {
- showTxnDetail({
- item,
- accountAddress: currentAccount?.address || '',
- mint,
- })
- },
- [currentAccount?.address, showTxnDetail, mint],
- )
-
- const hasAirdrop = useMemo(() => {
- if (cluster === 'devnet') {
- return (
- mint.equals(NATIVE_MINT) ||
- mint.equals(HNT_MINT) ||
- mint.equals(IOT_MINT) ||
- mint.equals(MOBILE_MINT)
- )
- }
- return false
- }, [mint, cluster])
-
- const renderHeader = useCallback(() => {
- const filterName = t(`accountsScreen.filterTypes.${filterState.filter}`)
-
- return (
-
-
- {filterName}
-
-
-
- {t('accountsScreen.filter')}
-
-
-
- )
- }, [filterState.filter, setBottomScreenHeaderHeight, t, toggleFiltersOpen])
-
- const keyExtractor = useCallback((item: Activity) => {
- return item.hash
- }, [])
-
- const renderItem = useCallback(
- ({ item, index }) => {
- const isFirst = index === 0
- const isLast = index === (activityData?.length || 0) - 1
- return (
-
-
-
-
-
- )
- },
- [
- activityData?.length,
- bottomScreenHeaderHeight,
- mint,
- now,
- showTransactionDetail,
- ],
- )
-
- const renderFooter = useCallback(() => {
- if (!activityLoading) {
- return (
- 0 ? 0 : bottomScreenHeaderHeight,
- }}
- >
-
- {t('accountsScreen.allFilterFooter')}
-
-
- )
- }
-
- return (
-
-
-
- )
- }, [activityData, activityLoading, bottomScreenHeaderHeight, t])
-
- const setFilter = useCallback(
- (filterType: FilterType) => () => {
- setFiltersOpen(false)
- filterState.change(filterType)
- },
- [filterState],
- )
-
- const filters = useCallback(
- () => (
- <>
- {!mint.equals(DC_MINT) && (
- <>
-
-
-
- >
- )}
- {mint.equals(DC_MINT) && (
- <>
-
-
- >
- )}
- >
- ),
- [filterState.filter, mint, setFilter, t],
- )
-
- const backgroundComponent = useCallback(
- () => ,
- [],
- )
-
- const stickyHeaderIndices = useMemo(() => [0], [])
-
- const handleHeaderLayout = useCallback(() => {
- headerContainerRef.current?.measure((...args) => {
- const [, , , height, , pageY] = args
- if (!height || !pageY) return
- setHeaderContainerYPos(height + pageY)
- })
- }, [])
-
- const handleTopHeaderLayout = useCallback(() => {
- topHeaderRef.current?.measure((...args) => {
- const [, , , height, , pageY] = args
-
- if (!height || !pageY) return
- setTopHeaderYPos(height + pageY)
- setTopHeaderHeight(height)
- })
- }, [setTopHeaderHeight])
-
- const actionBarProps = useMemo(() => {
- let options = {
- hasSend: true,
- hasRequest: true,
- hasDelegate: false,
- compact: true,
- hasBottomTitle: true,
- }
-
- if (mint.equals(DC_MINT)) {
- options = {
- hasSend: false,
- hasRequest: false,
- hasDelegate: true,
- compact: false,
- hasBottomTitle: false,
- }
- }
-
- return options
- }, [mint])
-
- return (
-
-
-
-
-
-
-
-
- {!!symbol && (
-
- )}
-
-
-
-
-
-
-
-
-
-
- {!!symbol && (
-
- )}
-
-
-
- {mint.equals(NATIVE_MINT) &&
- !isDevnet &&
- (amount || 0) < MIN_BALANCE_THRESHOLD ? (
- <>
-
-
- {t('accountsScreen.solWarning')}
-
-
- showModal({ type: 'InsufficientSolConversion' })
- }
- >
-
- {t('accountsScreen.solSwap')}
-
-
-
-
- >
- ) : (
-
- )}
-
-
-
- {!!canShowList && (
-
-
-
-
-
- )}
-
- {/* HACK FOR BACK GESTURE NOT WORKING ON IOS */}
- {Platform.OS === 'ios' && (
-
- )}
-
-
- {filters()}
-
-
- )
-}
-
-export default withTransactionDetail(AccountTokenScreen)
diff --git a/src/features/account/AccountsScreen.tsx b/src/features/account/AccountsScreen.tsx
deleted file mode 100644
index 62e566c10..000000000
--- a/src/features/account/AccountsScreen.tsx
+++ /dev/null
@@ -1,356 +0,0 @@
-import { ReAnimatedBox } from '@components/AnimatedBox'
-import Box from '@components/Box'
-import { NavBarHeight } from '@components/NavBar'
-import WarningBanner, { BannerType } from '@components/WarningBanner'
-import BottomSheet from '@gorhom/bottom-sheet'
-import { HNT_MINT } from '@helium/spl-utils'
-import useAppear from '@hooks/useAppear'
-import useDisappear from '@hooks/useDisappear'
-import useHaptic from '@hooks/useHaptic'
-import useLayoutHeight from '@hooks/useLayoutHeight'
-import useSolanaHealth from '@hooks/useSolanaHealth'
-import { useNavigation } from '@react-navigation/native'
-import { CSAccount } from '@storage/cloudStorage'
-import { useBackgroundStyle, useColors } from '@theme/themeHooks'
-import React, {
- memo,
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react'
-import { useAsync } from 'react-async-hook'
-import { Platform, View } from 'react-native'
-import { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import SharedGroupPreferences from 'react-native-shared-group-preferences'
-import { useSelector } from 'react-redux'
-import { RootNavigationProp } from '../../navigation/rootTypes'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
-import { useNotificationStorage } from '../../storage/NotificationStorageProvider'
-import { checkSecureAccount } from '../../storage/secureStorage'
-import { RootState } from '../../store/rootReducer'
-import { appSlice } from '../../store/slices/appSlice'
-import { useAppDispatch } from '../../store/store'
-import { AccountBalance } from '../../types/balance'
-import { useBalance } from '../../utils/Balance'
-import StatusBanner from '../StatusPage/StatusBanner'
-import { HomeNavigationProp } from '../home/homeTypes'
-import { useOnboarding } from '../onboarding/OnboardingProvider'
-import { OnboardingOpt } from '../onboarding/onboardingTypes'
-import AccountActionBar from './AccountActionBar'
-import AccountBalanceChart from './AccountBalanceChart'
-import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
-import AccountTokenList from './AccountTokenList'
-import AccountView from './AccountView'
-import AccountsTopNav from './AccountsTopNav'
-import { ITEM_HEIGHT } from './TokenListItem'
-import { withTransactionDetail } from './TransactionDetail'
-
-const AccountsScreen = () => {
- const widgetGroup = 'group.com.helium.mobile.wallet.widget'
- const navigation = useNavigation()
- const rootNav = useNavigation()
- const { sortedAccounts, currentAccount, defaultAccountAddress } =
- useAccountStorage()
- const [bannerHeight, setBannerHeight] = useLayoutHeight()
- const [navLayoutHeight, setNavLayoutHeight] = useLayoutHeight()
- const [pageHeight, setPageHeight] = useLayoutHeight(0)
- const { openedNotification } = useNotificationStorage()
- const { balanceHistory } = useBalance()
- const { locked, currency } = useAppStorage()
- const { cluster } = useSolana()
- const { reset } = useOnboarding()
- const [onboardingType, setOnboardingType] = useState('import')
- const [selectedBalance, setSelectedBalance] = useState()
- const { top } = useSafeAreaInsets()
- const bottomSheetRef = useRef(null)
- const listAnimatedPos = useSharedValue(0)
- const [topHeaderHeight, setTopHeaderHeight] = useState(0)
- const topHeaderRef = useRef(null)
- const bottomSheetStyle = useBackgroundStyle('surfaceSecondary')
- const dispatch = useAppDispatch()
- const { triggerImpact } = useHaptic()
- const colors = useColors()
- const { showBanner } = useSelector((state: RootState) => state.app)
- const { isHealthy } = useSolanaHealth()
-
- const actualTop = useMemo(() => {
- if (showBanner) {
- return 0
- }
- return top
- }, [top, showBanner])
-
- const actualBannerHeight = useMemo(() => {
- if (showBanner) {
- return bannerHeight
- }
- return 0
- }, [bannerHeight, showBanner])
-
- const snapPoints = useMemo(() => {
- if (!pageHeight) return undefined
- const collapsedHeight = ITEM_HEIGHT * 2
- // Get safe area top height
- const expandedHeight =
- pageHeight -
- navLayoutHeight -
- actualTop -
- topHeaderHeight -
- actualBannerHeight
- return [collapsedHeight, expandedHeight]
- }, [
- navLayoutHeight,
- pageHeight,
- actualTop,
- topHeaderHeight,
- actualBannerHeight,
- ])
-
- useAppear(() => {
- reset()
- })
-
- useDisappear(() => {
- setSelectedBalance(undefined)
- })
-
- // if user signs out from lockscreen
- useEffect(() => {
- if (sortedAccounts.length === 0) {
- rootNav.replace('OnboardingNavigator')
- }
- }, [rootNav, sortedAccounts.length])
-
- const showChart = useMemo(() => {
- return balanceHistory?.length >= 2
- }, [balanceHistory])
-
- const chartValues = useMemo(() => {
- // Need to have at least a two days of data to display
- if (!showChart) return
-
- return balanceHistory?.map((bh) => {
- return { y: bh.balance, info: bh }
- })
- }, [balanceHistory, showChart])
-
- useEffect(() => {
- if (currentAccount?.ledgerDevice) return
- // if current account is keystone account , check pass
- if (currentAccount?.keystoneDevice) return
- const address = currentAccount?.address
- if (address) checkSecureAccount(address)
- }, [
- currentAccount?.address,
- currentAccount?.ledgerDevice,
- currentAccount?.keystoneDevice,
- ])
-
- useEffect(() => {
- if (openedNotification && !locked) {
- // navigate to notifications if we are coming from tapping a push
- navigation.push('NotificationsNavigator')
- }
- }, [navigation, openedNotification, locked])
-
- useEffect(() => {
- if (!currentAccount?.address || onboardingType === 'import') return
-
- // Set onboarding back to import when navigating away
- setOnboardingType('import')
- }, [currentAccount?.address, onboardingType])
-
- // Hook that is used for helium balance widget.
- useAsync(async () => {
- if (Platform.OS === 'ios') {
- const defaultAccount = sortedAccounts.find(
- (account: CSAccount) => account.address === defaultAccountAddress,
- )
-
- await SharedGroupPreferences.setItem(
- 'heliumWalletWidgetKey',
- {
- defaultAccountAddress: defaultAccount?.solanaAddress,
- defaultAccountAlias: defaultAccount?.alias,
- currencyType: currency,
- cluster,
- },
- widgetGroup,
- )
- }
- }, [defaultAccountAddress, sortedAccounts])
-
- const toggleWalletsVisible = useCallback(() => {
- triggerImpact('light')
- dispatch(appSlice.actions.toggleConnectedWallets())
- setSelectedBalance(undefined)
- }, [dispatch, triggerImpact])
-
- const handleBalanceHistorySelected = useCallback(
- (accountBalance?: AccountBalance) => {
- setSelectedBalance(accountBalance)
- },
- [],
- )
-
- const onTouchStart = useCallback(() => {
- handleBalanceHistorySelected(undefined)
- }, [handleBalanceHistorySelected])
-
- const animatedStyle = useAnimatedStyle(() => {
- if (!snapPoints) {
- return {
- opacity: 1,
- paddingBottom: 0,
- display: 'flex',
- }
- }
-
- const realHeight = pageHeight + NavBarHeight
- const diff = realHeight - listAnimatedPos.value
- const opacity =
- (listAnimatedPos.value -
- actualTop -
- topHeaderHeight -
- navLayoutHeight -
- actualBannerHeight -
- pageHeight * 0.3) /
- (snapPoints[1] - snapPoints[0] - pageHeight * 0.3)
-
- return {
- opacity,
- paddingBottom: diff - NavBarHeight,
- display: opacity <= 0 ? 'none' : 'flex',
- }
- })
-
- const headerAnimatedStyle = useAnimatedStyle(() => {
- if (!snapPoints) {
- return {
- opacity: 0,
- position: 'absolute',
- top: actualTop + navLayoutHeight + actualBannerHeight,
- left: 0,
- right: 0,
- }
- }
-
- const opacity =
- (listAnimatedPos.value -
- actualTop -
- topHeaderHeight -
- navLayoutHeight -
- actualBannerHeight) /
- (snapPoints[1] - snapPoints[0])
-
- return {
- opacity: 1 - opacity,
- position: 'absolute',
- top: actualTop + navLayoutHeight + actualBannerHeight,
- left: 0,
- right: 0,
- }
- })
-
- const handleTopHeaderLayout = useCallback(() => {
- topHeaderRef.current?.measure((...args) => {
- const [, , , height, , pageY] = args
-
- if (!height || !pageY) return
- setTopHeaderHeight(height)
- })
- }, [setTopHeaderHeight])
-
- const RetractedView = useMemo(() => {
- return (
-
-
-
-
-
-
- )
- }, [handleTopHeaderLayout, headerAnimatedStyle])
-
- const handleIndicatorStyle = useMemo(() => {
- return {
- backgroundColor: colors.secondaryText,
- }
- }, [colors.secondaryText])
-
- const bannerVisible = useMemo(() => {
- if (cluster === 'devnet') {
- return true
- }
- return !isHealthy
- }, [cluster, isHealthy])
-
- return (
-
-
- {bannerVisible && (
-
- )}
-
- {RetractedView}
- {currentAccount?.address && (
-
-
-
- {chartValues && (
-
- )}
-
-
- )}
-
-
-
-
-
-
- )
-}
-
-export default memo(withTransactionDetail(AccountsScreen))
diff --git a/src/features/account/AccountsTopNav.tsx b/src/features/account/AccountsTopNav.tsx
deleted file mode 100644
index 0c6e40928..000000000
--- a/src/features/account/AccountsTopNav.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import AccountIco from '@assets/images/account.svg'
-import CarotDown from '@assets/images/carot-down.svg'
-import CogIco from '@assets/images/cog.svg'
-import NotificationsBellIco from '@assets/images/notificationBell.svg'
-import AccountIcon from '@components/AccountIcon'
-import Box from '@components/Box'
-import IconPressedContainer from '@components/IconPressedContainer'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import useHaptic from '@hooks/useHaptic'
-import useSolanaHealth from '@hooks/useSolanaHealth'
-import { useNavigation } from '@react-navigation/native'
-import { useColors } from '@theme/themeHooks'
-import React, { useCallback, useMemo } from 'react'
-import { LayoutChangeEvent } from 'react-native'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import { useSelector } from 'react-redux'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { HomeNavigationProp } from '../home/homeTypes'
-import { RootState } from '../../store/rootReducer'
-
-type Props = {
- onPressWallet: () => void
- onLayout?: (event: LayoutChangeEvent) => void
-}
-const AccountsTopNav = ({ onPressWallet, onLayout }: Props) => {
- const { primaryText } = useColors()
- const navigation = useNavigation()
- const { currentAccount, currentNetworkAddress } = useAccountStorage()
- const { cluster } = useSolana()
- const { triggerImpact } = useHaptic()
- const { showBanner } = useSelector((state: RootState) => state.app)
- const { isHealthy } = useSolanaHealth()
-
- const notificationsByResource = useSelector(
- (appState: RootState) => appState.notifications.notifications,
- )
-
- const hasUnreadNotifications = useMemo(() => {
- const allNotifs = Object.keys(notificationsByResource).flatMap(
- (k) => notificationsByResource[k],
- )
-
- const unread = allNotifs.find((n) => !n.viewedAt)
- return !!unread
- }, [notificationsByResource])
-
- const navToSettings = useCallback(() => {
- triggerImpact('light')
- navigation.navigate('SettingsNavigator')
- }, [navigation, triggerImpact])
-
- const navToNotifs = useCallback(() => {
- triggerImpact('light')
- navigation.push('NotificationsNavigator')
- }, [navigation, triggerImpact])
-
- const navToAddressBook = useCallback(() => {
- triggerImpact('light')
- navigation.push('AddressBookNavigator')
- }, [navigation, triggerImpact])
-
- const { top } = useSafeAreaInsets()
-
- const bannerVisible = useMemo(() => {
- if (cluster === 'devnet') {
- return true
- }
- return !isHealthy
- }, [cluster, isHealthy])
-
- const containerStyle = useMemo(
- () => ({ marginTop: bannerVisible && showBanner ? 0 : top }),
- [top, bannerVisible, showBanner],
- )
-
- return (
-
-
-
-
-
-
-
-
-
-
- {currentAccount?.alias}
-
-
-
-
-
-
-
-
- {hasUnreadNotifications && (
-
-
-
- )}
-
-
-
-
-
-
- )
-}
-
-export default AccountsTopNav
diff --git a/src/features/account/ConnectedWallets.tsx b/src/features/account/ConnectedWallets.tsx
deleted file mode 100644
index 228e5fa72..000000000
--- a/src/features/account/ConnectedWallets.tsx
+++ /dev/null
@@ -1,412 +0,0 @@
-import Add from '@assets/images/add.svg'
-import Checkmark from '@assets/images/checkmark.svg'
-import AccountIcon from '@components/AccountIcon'
-import BackgroundFill from '@components/BackgroundFill'
-import Box from '@components/Box'
-import Text from '@components/Text'
-import TouchableContainer from '@components/TouchableContainer'
-import {
- BottomSheetBackdrop,
- BottomSheetModal,
- BottomSheetModalProvider,
- BottomSheetSectionList,
-} from '@gorhom/bottom-sheet'
-import { NetTypes } from '@helium/address'
-import useBackHandler from '@hooks/useBackHandler'
-import useLayoutHeight from '@hooks/useLayoutHeight'
-import { useNavigation } from '@react-navigation/native'
-import { useColors, useOpacity } from '@theme/themeHooks'
-import React, {
- ReactNode,
- Ref,
- forwardRef,
- memo,
- useCallback,
- useEffect,
- useImperativeHandle,
- useMemo,
- useRef,
- useState,
-} from 'react'
-import { useTranslation } from 'react-i18next'
-import { LayoutChangeEvent } from 'react-native'
-import { initialWindowMetrics } from 'react-native-safe-area-context'
-import { TabBarNavigationProp } from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
-import { CSAccount } from '../../storage/cloudStorage'
-import { useOnboarding } from '../onboarding/OnboardingProvider'
-
-export type ConnectedWalletsRef = {
- show: () => void
- hide: () => void
-}
-
-type Props = {
- onClose?: () => void
- onAddNew: () => void
- onAddSub: (acc: CSAccount) => void
- children: ReactNode
-}
-
-const ConnectedWallets = forwardRef(
- (
- { onClose, onAddNew, onAddSub, children }: Props,
- ref: Ref,
- ) => {
- useImperativeHandle(ref, () => ({ show, hide }))
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const keyExtractor = useCallback((item) => item.address, [])
- const { primaryText, secondaryText } = useColors()
- const { t } = useTranslation()
- const bottomSheetModalRef = useRef(null)
- const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
- const [listItemHeight, setListItemHeight] = useLayoutHeight()
- const [sectionHeaderHeight, setSectionHeaderHeight] = useLayoutHeight()
- const [footerHeight, setFooterHeight] = useLayoutHeight()
- const [sectionFooterHeights, setSectionFooterHeights] = useState<{
- [key: string]: number
- }>({})
- const sectionFooterHeight = useMemo(
- () =>
- Object.values(sectionFooterHeights).reduce(
- (acc, height) => acc + height,
- 0,
- ),
- [sectionFooterHeights],
- )
-
- const { sortedAccounts, currentAccount, setCurrentAccount } =
- useAccountStorage()
- useEffect(() => {
- const hashes = new Set(
- sortedAccounts.map((a) => a.mnemonicHash || 'none'),
- )
- setSectionFooterHeights((prev) =>
- Object.entries(prev)
- .filter(([key]) => hashes.has(key))
- .reduce((acc, [key, height]) => ({ ...acc, [key]: height }), {}),
- )
- }, [sortedAccounts])
- const navigation = useNavigation()
- const { enableTestnet } = useAppStorage()
-
- const filteredAccounts = useMemo(() => {
- const grouped = sortedAccounts
- .filter((a) => a.netType !== NetTypes.TESTNET)
- .reduce((acc, account) => {
- acc[account.mnemonicHash || 'none'] = [
- ...(acc[account.mnemonicHash || 'none'] || []),
- account,
- ]
- return acc
- }, {} as { [key: string]: CSAccount[] })
-
- const { none, ...rest } = grouped
- const ret = Object.values(rest).map((accounts, index) => ({
- title: `Seed Phrase ${index + 1}`,
- data: accounts,
- }))
- if (none) {
- ret.push({
- title: 'Private Keys',
- data: none,
- })
- }
-
- return ret
- }, [sortedAccounts])
-
- const snapPoints = useMemo(() => {
- const totalHeight =
- listItemHeight &&
- footerHeight &&
- sectionHeaderHeight &&
- sortedAccounts.length &&
- listItemHeight * (sortedAccounts.length + (enableTestnet ? 2 : 1)) +
- footerHeight +
- sectionHeaderHeight * filteredAccounts.length +
- sectionFooterHeight
-
- return [
- totalHeight &&
- totalHeight < 0.7 * (initialWindowMetrics?.frame.height || 0)
- ? totalHeight
- : '70%',
- ]
- }, [
- footerHeight,
- enableTestnet,
- filteredAccounts,
- listItemHeight,
- sortedAccounts.length,
- sectionFooterHeight,
- sectionHeaderHeight,
- ])
-
- const { setOnboardingData } = useOnboarding()
-
- const show = useCallback(() => {
- bottomSheetModalRef.current?.present()
- setIsShowing(true)
- }, [setIsShowing])
-
- const hide = useCallback(() => {
- bottomSheetModalRef.current?.dismiss()
- setIsShowing(false)
- }, [setIsShowing])
-
- const handleNetTypeChange = useCallback(
- (nextNetType?: NetTypes.NetType) => {
- setOnboardingData((prev) => {
- let netType = nextNetType
- if (netType === undefined) {
- netType =
- prev.netType === NetTypes.MAINNET
- ? NetTypes.TESTNET
- : NetTypes.MAINNET
- }
- return { ...prev, netType }
- })
- },
- [setOnboardingData],
- )
-
- const handleAddNew = useCallback(
- (netType: NetTypes.NetType) => () => {
- hide()
- handleNetTypeChange(netType)
- onAddNew()
- },
- [handleNetTypeChange, onAddNew, hide],
- )
-
- const handleAccountChange = useCallback(
- (item: CSAccount) => () => {
- hide()
- setCurrentAccount(item)
- // Reset Home & Collectables stack to first screen
- navigation.reset({
- index: 0,
- routes: [{ name: 'Home' }],
- })
- },
- [hide, setCurrentAccount, navigation],
- )
-
- const renderItem = useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item }: { index: number; item: CSAccount }) => {
- const isSelected = item.address === currentAccount?.address
- const accountAddress = item?.solanaAddress
- return (
-
- {item.netType === NetTypes.TESTNET && (
-
- )}
-
-
- {item.alias}
-
-
- {isSelected && (
-
- )}
-
-
- )
- },
- [
- currentAccount?.address,
- handleAccountChange,
- primaryText,
- setListItemHeight,
- ],
- )
-
- const footer = useCallback(
- () => (
-
-
-
-
- {t('connectedWallets.add')}
-
-
-
- {enableTestnet && (
-
-
-
-
- {t('connectedWallets.addTestnet')}
-
-
- )}
-
- ),
- [enableTestnet, handleAddNew, primaryText, t, setFooterHeight],
- )
-
- const renderBackdrop = useCallback(
- (props) => (
-
- ),
- [],
- )
-
- const handleModalDismiss = useCallback(() => {
- handleDismiss()
- if (onClose) {
- onClose()
- }
- }, [handleDismiss, onClose])
-
- const handleIndicatorStyle = useMemo(() => {
- return {
- backgroundColor: secondaryText,
- }
- }, [secondaryText])
-
- const sectionFooter = useCallback(
- ({ section: { data } }) => {
- return (
- {
- setSectionFooterHeights((prev) => {
- const newHeight = { ...prev }
- if (height.nativeEvent) {
- newHeight[data[0].mnemonicHash || 'none'] =
- height.nativeEvent.layout.height
- }
-
- return newHeight
- })
- }}
- />
- )
- },
- [onAddSub, currentAccount?.mnemonicHash],
- )
-
- return (
-
- {children}
-
- (
-
-
- {title}
-
-
- )}
- renderSectionFooter={sectionFooter}
- />
-
-
- )
- },
-)
-
-const SectionFooter: React.FC<{
- data: CSAccount[]
- isSelected: boolean
- onAddSub: (acc: CSAccount) => void
- onLayout: (height: LayoutChangeEvent) => void
-}> = ({ data, onAddSub, onLayout, isSelected }) => {
- const handleAddSub = useCallback(() => {
- if (data[0] && data[0].mnemonicHash) {
- onAddSub(data[data.length - 1])
- }
- }, [data, onAddSub])
- const { primaryText } = useColors()
- const { t } = useTranslation()
- return (
-
- {isSelected && data[0] && data[0].mnemonicHash ? (
-
-
-
- {t('connectedWallets.addSub')}
-
-
- ) : null}
-
- )
-}
-
-export default memo(ConnectedWallets)
diff --git a/src/features/account/TokenListItem.tsx b/src/features/account/TokenListItem.tsx
deleted file mode 100644
index db3e413ba..000000000
--- a/src/features/account/TokenListItem.tsx
+++ /dev/null
@@ -1,345 +0,0 @@
-/* eslint-disable @typescript-eslint/no-shadow */
-import Arrow from '@assets/images/listItemRight.svg'
-import Lock from '@assets/images/lockClosed.svg'
-import InfoWarning from '@assets/images/warning.svg'
-import Box from '@components/Box'
-import FadeInOut from '@components/FadeInOut'
-import Text from '@components/Text'
-import TokenIcon from '@components/TokenIcon'
-import TouchableContainer from '@components/TouchableContainer'
-import { useMint, useOwnedAmount } from '@helium/helium-react-hooks'
-import {
- useHeliumVsrState,
- usePositions,
-} from '@helium/voter-stake-registry-hooks'
-import { getPositionKeysForOwner } from '@helium/voter-stake-registry-sdk'
-import { useCurrentWallet } from '@hooks/useCurrentWallet'
-import useHaptic from '@hooks/useHaptic'
-import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
-import usePrevious from '@hooks/usePrevious'
-import { useNavigation } from '@react-navigation/native'
-import { NATIVE_MINT } from '@solana/spl-token'
-import { PublicKey } from '@solana/web3.js'
-import { useColors } from '@theme/themeHooks'
-import { MIN_BALANCE_THRESHOLD } from '@utils/constants'
-import { humanReadable } from '@utils/solanaUtils'
-import BN from 'bn.js'
-import React, { useCallback, useMemo } from 'react'
-import { useAsync } from 'react-async-hook'
-import { useSolana } from '../../solana/SolanaProvider'
-import { HomeNavigationProp } from '../home/homeTypes'
-import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
-
-export const ITEM_HEIGHT = 72
-type Props = {
- mint: PublicKey
-}
-
-export const TokenSkeleton = () => {
- return (
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export const TokenListItem = ({ mint }: Props) => {
- const navigation = useNavigation()
- const wallet = useCurrentWallet()
- const {
- amount,
- decimals,
- loading: loadingOwned,
- } = useOwnedAmount(wallet, mint)
- const { triggerImpact } = useHaptic()
- const { json, symbol, loading } = useMetaplexMetadata(mint)
- const mintStr = mint.toBase58()
-
- const handleNavigation = useCallback(() => {
- triggerImpact('light')
- navigation.navigate('AccountTokenScreen', {
- mint: mintStr,
- })
- }, [navigation, mintStr, triggerImpact])
-
- const balanceToDisplay = useMemo(() => {
- return amount && typeof decimals !== 'undefined'
- ? humanReadable(new BN(amount.toString()), decimals)
- : '0'
- }, [amount, decimals])
-
- return (
-
-
- {loading ? (
-
- ) : (
-
- )}
-
-
- {loadingOwned ? (
-
-
-
-
- ) : (
-
-
-
- {`${balanceToDisplay} `}
-
-
- {symbol}
-
-
- {symbol && (
-
- )}
-
- )}
-
- {mint.equals(NATIVE_MINT) && (amount || 0) < MIN_BALANCE_THRESHOLD && (
-
-
-
- )}
-
-
-
- )
-}
-
-export const TokenListGovItem = ({ mint }: { mint: PublicKey }) => {
- const navigation = useNavigation()
- const { anchorProvider, connection } = useSolana()
- const wallet = useCurrentWallet()
- const { triggerImpact } = useHaptic()
- const { json, symbol, loading } = useMetaplexMetadata(mint)
- const decimals = useMint(mint)?.info?.decimals
- const mintStr = mint.toBase58()
- const colors = useColors()
- const {
- positions: contextPositions,
- mint: govMint,
- loading: loadingContext,
- } = useHeliumVsrState()
- const useContextPositions = useMemo(
- () => !!govMint?.equals(mint),
- [govMint, mint],
- )
-
- const args = useMemo(
- () =>
- wallet &&
- mint &&
- connection && {
- wallet,
- mint,
- provider: anchorProvider,
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [wallet?.toBase58(), mint.toBase58(), connection, anchorProvider],
- )
-
- const { result, loading: loadingPositionKeys } = useAsync(
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- async (args: any | undefined, useContext: boolean) => {
- if (args && !useContext) {
- return getPositionKeysForOwner(args)
- }
- },
- [args, useContextPositions],
- )
-
- const { accounts: fetchedPositions, loading: loadingFetchedPositions } =
- usePositions(result?.positions)
- const loadingPositions = loadingFetchedPositions || loadingContext
- const positions = useMemo(
- () =>
- useContextPositions
- ? contextPositions
- : fetchedPositions?.map((fetched) => fetched.info),
- [useContextPositions, contextPositions, fetchedPositions],
- )
-
- const { amountLocked } = useMemo(() => {
- if (positions && positions.length) {
- let amountLocked = new BN(0)
- positions.forEach((position) => {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- if (position && !position.isProxiedToMe) {
- amountLocked = amountLocked.add(position.amountDepositedNative)
- }
- })
-
- return {
- amountLocked,
- }
- }
-
- return {}
- }, [positions])
-
- const prevLocked = usePrevious(amountLocked)
-
- const handleNavigation = useCallback(() => {
- triggerImpact('light')
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- ;(navigation as any).navigate('Governance', {
- screen: 'PositionsScreen',
- initial: false,
- params: { mint: mintStr },
- })
- }, [navigation, mintStr, triggerImpact])
-
- const balanceToDisplay = useMemo(() => {
- return amountLocked && typeof decimals !== 'undefined'
- ? humanReadable(new BN(amountLocked.toString()), decimals)
- : '0'
- }, [amountLocked, decimals])
-
- const loadingAmount = useMemo(() => {
- return !prevLocked && (loadingPositionKeys || loadingPositions)
- }, [loadingPositionKeys, loadingPositions, prevLocked])
-
- return (
-
-
- {loading ? (
-
- ) : (
-
-
-
-
-
-
-
-
- )}
-
-
- {loadingAmount ? (
-
-
-
-
- ) : (
-
-
-
- {`${balanceToDisplay} `}
-
-
- {symbol} (Locked)
-
-
- -
-
- )}
-
-
-
-
- )
-}
diff --git a/src/features/account/TransactionDetail.tsx b/src/features/account/TransactionDetail.tsx
deleted file mode 100644
index 5e8d7c046..000000000
--- a/src/features/account/TransactionDetail.tsx
+++ /dev/null
@@ -1,219 +0,0 @@
-/* eslint-disable react/no-array-index-key */
-import BlurBox from '@components/BlurBox'
-import HandleBasic from '@components/HandleBasic'
-import SafeAreaBox from '@components/SafeAreaBox'
-import {
- BottomSheetBackdrop,
- BottomSheetModal,
- BottomSheetModalProvider,
- BottomSheetScrollView,
-} from '@gorhom/bottom-sheet'
-import useBackHandler from '@hooks/useBackHandler'
-import { PublicKey } from '@solana/web3.js'
-import React, {
- FC,
- ReactNode,
- createContext,
- useCallback,
- useContext,
- useMemo,
- useRef,
- useState,
-} from 'react'
-import { useTranslation } from 'react-i18next'
-import { LayoutChangeEvent } from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
-import { useCreateExplorerUrl } from '../../constants/urls'
-import { Activity } from '../../types/activity'
-import TransactionLineItem from './TransactionLineItem'
-import { useTxnDetails } from './useTxn'
-
-const initialState = {
- show: () => undefined,
-}
-
-type DetailData = { item: Activity; accountAddress: string; mint: PublicKey }
-type TransactionDetailSelectorActions = {
- show: (data: DetailData) => void
-}
-const TransactionDetailSelectorContext =
- createContext(initialState)
-const { Provider } = TransactionDetailSelectorContext
-
-const TransactionDetailSelector = ({ children }: { children: ReactNode }) => {
- const { t } = useTranslation()
- const bottomSheetModalRef = useRef(null)
- const [detailData, setDetailData] = useState()
- const [contentHeight, setContentHeight] = useState(0)
- const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
-
- const { item: txn, mint } = detailData || {}
-
- const {
- amount,
- amountTitle,
- color,
- fee,
- feePayer,
- icon,
- paymentsReceived,
- paymentsSent,
- time,
- title,
- } = useTxnDetails(mint, txn)
- const createExplorerUrl = useCreateExplorerUrl()
-
- const snapPoints = useMemo(() => {
- let maxHeight: number | string = '90%'
- if (contentHeight > 0) {
- maxHeight = contentHeight
- }
- return ['50%', maxHeight]
- }, [contentHeight])
-
- const show = useCallback(
- (data: DetailData) => {
- setDetailData(data)
- bottomSheetModalRef.current?.present()
- setIsShowing(true)
- },
- [setIsShowing],
- )
-
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
-
- const renderBackdrop = useCallback(
- (props) => (
-
- ),
- [],
- )
-
- const backgroundComponent = useCallback(() => {
- return (
-
- )
- }, [])
-
- const handleComponent = useCallback(() => , [])
-
- const handleContentLayout = useCallback((e: LayoutChangeEvent) => {
- setContentHeight(e.nativeEvent.layout.height)
- }, [])
-
- return (
-
-
-
-
-
-
-
- {paymentsSent.map(({ amount: amt }, index) => (
-
-
-
- ))}
-
- {paymentsReceived.map(({ amount: amt }, index) => (
-
-
-
- ))}
-
- {!!amountTitle && (
-
- )}
-
- {!!fee && (
-
- )}
-
-
-
- {!txn?.pending && (
-
- )}
-
-
-
-
-
- {children}
-
-
- )
-}
-
-export const useTransactionDetail = () =>
- useContext(TransactionDetailSelectorContext)
-
-export const withTransactionDetail = (Component: FC) => () => {
- return (
-
-
-
- )
-}
diff --git a/src/features/activity/ActivityDetailsScreen.tsx b/src/features/activity/ActivityDetailsScreen.tsx
index 0093c4bf7..007ee08b5 100644
--- a/src/features/activity/ActivityDetailsScreen.tsx
+++ b/src/features/activity/ActivityDetailsScreen.tsx
@@ -1,13 +1,11 @@
-import Error from '@assets/images/error.svg'
-import Receive from '@assets/images/receive.svg'
-import Send from '@assets/images/send.svg'
-import { ReAnimatedBox } from '@components/AnimatedBox'
+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'
import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
-import { DelayedFadeIn } from '@components/FadeInOut'
import ImageBox from '@components/ImageBox'
import ListItem from '@components/ListItem'
import Text from '@components/Text'
@@ -16,12 +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 globalStyles from '@theme/globalStyles'
-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, ScrollView } from 'react-native'
-import { useCreateExplorerUrl } from '../../constants/urls'
+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 '../../utils/constants/urls'
import { EnrichedTransaction } from '../../types/solana'
import { ellipsizeAddress, solAddressIsValid } from '../../utils/accountUtils'
import AddressActivityItem from './AddressActivityItem'
@@ -46,7 +46,7 @@ function ScamWarningImageBox(props: any): React.ReactElement {
>
{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
}}
>
-
+
{t('activityScreen.scamWarning')}
setDismissed(true)}
- borderRadius="round"
- borderColor="red500"
+ borderRadius="full"
+ borderColor="error.500"
borderWidth={1}
- px="m"
- titleColorDisabled="black500"
- titleColor="red500"
+ px="4"
+ titleColorDisabled="gray.800"
+ titleColor="error.500"
fontWeight="500"
- marginTop="l"
+ marginTop="6"
/>
@@ -82,6 +82,7 @@ function ScamWarningImageBox(props: any): React.ReactElement {
}
const ActivityDetailsScreen = () => {
+ const { bottom } = useSafeAreaInsets()
const route = useRoute()
const colors = useColors()
const { t, i18n } = useTranslation()
@@ -128,7 +129,7 @@ const ActivityDetailsScreen = () => {
const confirmedSig = transaction as ConfirmedSignatureInfo
if (enrichedTx.transactionError || confirmedSig.err) {
- return
+ return
}
const userSignedTransaction =
wallet && enrichedTx.signers?.includes(wallet.toBase58())
@@ -141,8 +142,8 @@ const ActivityDetailsScreen = () => {
if (!nft?.metadata.image) {
return (
{
}}
width={250}
height={250}
- borderRadius="xxl"
+ borderRadius="4xl"
/>
)
}
@@ -178,15 +179,15 @@ const ActivityDetailsScreen = () => {
}}
width={250}
height={250}
- borderRadius="xxl"
+ borderRadius="4xl"
/>
)
}
return userSignedTransaction ? (
-
+
) : (
-
+
)
}, [colors, transaction, wallet])
@@ -224,13 +225,13 @@ const ActivityDetailsScreen = () => {
}
return (
-
+
{fromAccount && (
@@ -238,8 +239,8 @@ const ActivityDetailsScreen = () => {
{toAccount && (
)}
@@ -342,67 +343,75 @@ const ActivityDetailsScreen = () => {
)
return (
-
-
+
-
-
-
- {activityImage}
-
- {title}
-
-
- {description}
-
-
- {dateLabel}
-
-
- {AccountAddressListItems}
-
-
-
+
+
+ {activityImage}
+
+ {title}
+
+
+ {description}
+
+
+ {dateLabel}
+
-
- {accountOptions()}
-
-
-
-
+ {AccountAddressListItems}
+
+
+
+
+
+ {accountOptions()}
+
+
+
)
}
diff --git a/src/features/activity/ActivityListItem.tsx b/src/features/activity/ActivityListItem.tsx
index 7748c5658..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'
@@ -95,26 +95,26 @@ const ActivityListItem = ({
return (
{!transactionFailed ? (
userSignedTransaction ? (
-
+
) : (
-
+
)
) : (
-
+
)}
-
- {title}
-
+
+ {title}
+
{subtitle}
diff --git a/src/features/activity/ActivityScreen.tsx b/src/features/activity/ActivityScreen.tsx
index d10d4190d..fabd8a027 100644
--- a/src/features/activity/ActivityScreen.tsx
+++ b/src/features/activity/ActivityScreen.tsx
@@ -1,20 +1,19 @@
import React, { useCallback, useMemo } from 'react'
-import { RefreshControl, SectionList } from 'react-native'
+import { Image, RefreshControl, SectionList } from 'react-native'
import { EnrichedTransaction } from 'src/types/solana'
import { ConfirmedSignatureInfo } from '@solana/web3.js'
import { useNavigation } from '@react-navigation/native'
import { useTranslation } from 'react-i18next'
-import { Edge } from 'react-native-safe-area-context'
-import SafeAreaBox from '@components/SafeAreaBox'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import Box from '@components/Box'
import Text from '@components/Text'
import useEnrichedTransactions from '@hooks/useEnrichedTransactions'
import CircleLoader from '@components/CircleLoader'
-import FadeInOut, { DelayedFadeIn } from '@components/FadeInOut'
-import { ReAnimatedBox } from '@components/AnimatedBox'
+import FadeInOut from '@components/FadeInOut'
import useHaptic from '@hooks/useHaptic'
-import globalStyles from '@theme/globalStyles'
-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'
import ActivityListItem from './ActivityListItem'
@@ -23,15 +22,17 @@ const ActivityScreen = () => {
useEnrichedTransactions()
const { t } = useTranslation()
const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
const colors = useColors()
const navigation = useNavigation()
const { triggerImpact } = useHaptic()
const contentContainer = useMemo(
() => ({
- paddingBottom: spacing.xxxl,
+ paddingTop: spacing['6xl'],
+ paddingBottom: NavBarHeight + bottom + spacing['6xl'],
}),
- [spacing.xxxl],
+ [spacing, bottom],
)
const SectionData = useMemo((): {
@@ -80,13 +81,13 @@ const ActivityScreen = () => {
-
+
{title}
@@ -96,15 +97,22 @@ const ActivityScreen = () => {
const renderHeader = useCallback(() => {
return (
-
-
+
+
+
{t('activityScreen.title')}
+
+ {t('activityScreen.subtitle')}
+
)
}, [t])
@@ -119,8 +127,6 @@ const ActivityScreen = () => {
[navigation, triggerImpact],
)
- const safeEdges = useMemo(() => ['top'] as Edge[], [])
-
const renderItem = useCallback(
({ item, index, section }) => {
const firstItem = index === 0
@@ -134,7 +140,7 @@ const ActivityScreen = () => {
borderBottomStartRadius={lastItem ? 'xl' : undefined}
borderBottomEndRadius={lastItem ? 'xl' : undefined}
hasDivider={!lastItem || (firstItem && section.data.length !== 1)}
- marginHorizontal="m"
+ marginHorizontal="4"
transaction={item}
onPress={handleActivityItemPress(item)}
/>
@@ -146,7 +152,7 @@ const ActivityScreen = () => {
const Footer = useCallback(() => {
return fetchingMore ? (
-
+
) : null
@@ -155,30 +161,34 @@ const ActivityScreen = () => {
const keyExtractor = useCallback((item, index) => item.signature + index, [])
return (
-
-
-
- }
- onEndReachedThreshold={0.05}
- onEndReached={fetchMore}
- ListFooterComponent={Footer}
+
-
-
+ }
+ >
+
+
)
}
diff --git a/src/features/activity/AddressActivityItem.tsx b/src/features/activity/AddressActivityItem.tsx
index 1524e7c07..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
@@ -32,29 +32,33 @@ const AddressActivityItem = ({
return (
<>
-
+
{currentAccount &&
currentAccount.solanaAddress === accountAddress && (
- {t('activityScreen.myAccount')}
+
+ {t('activityScreen.myAccount')}
+
)}
- {ellipsizeAddress(accountAddress)}
+
+ {ellipsizeAddress(accountAddress)}
+
-
-
+
+
{showBubbleArrow && (
diff --git a/src/features/addressBook/AddressBook.tsx b/src/features/addressBook/AddressBook.tsx
index a762a4061..57403a3b2 100644
--- a/src/features/addressBook/AddressBook.tsx
+++ b/src/features/addressBook/AddressBook.tsx
@@ -1,26 +1,19 @@
import React, { memo, useCallback } from 'react'
import { useNavigation } from '@react-navigation/native'
import { useTranslation } from 'react-i18next'
-import { Platform } from 'react-native'
import Box from '@components/Box'
-import Text from '@components/Text'
-import CloseButton from '@components/CloseButton'
-import { CSAccount } from '@storage/cloudStorage'
-import { HomeNavigationProp } from '../home/homeTypes'
+import { CSAccount } from '@config/storage/cloudStorage'
+import BackScreen from '@components/BackScreen'
+import ScrollBox from '@components/ScrollBox'
import ContactsList from './ContactsList'
import { AddressBookNavigationProp } from './addressBookTypes'
const AddressBook = () => {
const { t } = useTranslation()
- const homeNav = useNavigation()
const addressNav = useNavigation()
- const onRequestClose = useCallback(() => {
- homeNav.goBack()
- }, [homeNav])
-
const handleAddNewContact = useCallback(() => {
- addressNav.navigate('AddNewContact')
+ addressNav.push('AddNewContact')
}, [addressNav])
const handleEditContact = useCallback(
@@ -31,28 +24,21 @@ const AddressBook = () => {
)
return (
-
-
+
-
- {t('addressBook.title')}
-
-
+
-
-
-
+
+
)
}
diff --git a/src/features/addressBook/AddressBookNavigator.tsx b/src/features/addressBook/AddressBookNavigator.tsx
index 48fe6df6b..875500689 100644
--- a/src/features/addressBook/AddressBookNavigator.tsx
+++ b/src/features/addressBook/AddressBookNavigator.tsx
@@ -1,23 +1,30 @@
-import React, { memo } from 'react'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { useOpacity } from '@theme/themeHooks'
+import React, { memo, useMemo } from 'react'
+import { useColors } from '@config/theme/themeHooks'
+import {
+ createStackNavigator,
+ StackNavigationOptions,
+} from '@react-navigation/stack'
import AddressBook from './AddressBook'
import AddNewContact from './AddNewContact'
import EditContact from './EditContact'
import AddressQrScanner from './AddressQrScanner'
-const AddressBookStack = createNativeStackNavigator()
+const AddressBookStack = createStackNavigator()
const AddressBookNavigator = () => {
- const { backgroundStyle } = useOpacity('primaryBackground', 0.98)
- return (
-
+ ({
headerShown: false,
- contentStyle: backgroundStyle,
- presentation: 'modal',
- }}
- >
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ } as StackNavigationOptions),
+ [colors],
+ )
+
+ return (
+
diff --git a/src/features/addressBook/AddressExtra.tsx b/src/features/addressBook/AddressExtra.tsx
index 5fc09334b..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 = {
@@ -16,17 +16,17 @@ const AddressExtra = ({
onScanPress,
}: AddressExtraProps) => {
const colors = useColors()
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
if (addressLoading) {
- return
+ return
}
if (isValidAddress) {
- return
+ return
}
return (
-
+
)
}
diff --git a/src/features/addressBook/AddressQrScanner.tsx b/src/features/addressBook/AddressQrScanner.tsx
index fc6962164..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 { HomeNavigationProp } from '../home/homeTypes'
-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'
@@ -14,7 +14,7 @@ const AddressQrScanner = () => {
const { setScannedAddress } = useAppStorage()
const { showOKAlert } = useAlert()
const { t } = useTranslation()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const handleBarCodeScanned = useCallback(
async (data: string) => {
diff --git a/src/features/addressBook/ContactDetails.tsx b/src/features/addressBook/ContactDetails.tsx
index b1566410d..f1ab9981d 100644
--- a/src/features/addressBook/ContactDetails.tsx
+++ b/src/features/addressBook/ContactDetails.tsx
@@ -15,31 +15,32 @@ import {
TextInput as RNTextInput,
Platform,
} from 'react-native'
-import Checkmark from '@assets/images/checkmark.svg'
-import { useKeyboard } from '@react-native-community/hooks'
+import Checkmark from '@assets/svgs/checkmark.svg'
import Box from '@components/Box'
import Text from '@components/Text'
-import { useColors, useOpacity, useSpacing } from '@theme/themeHooks'
-import SafeAreaBox from '@components/SafeAreaBox'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import TextInput from '@components/TextInput'
import ButtonPressable from '@components/ButtonPressable'
import AccountIcon from '@components/AccountIcon'
import useAlert from '@hooks/useAlert'
-import CloseButton from '@components/CloseButton'
import { solAddressIsValid, accountNetType } from '@utils/accountUtils'
import { heliumAddressFromSolAddress } from '@helium/spl-utils'
import { useDebounce } from 'use-debounce'
import { fetchDomainOwner } from '@utils/getDomainOwner'
-import { HomeNavigationProp } from '../home/homeTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
+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 '@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
@@ -51,17 +52,15 @@ type Props = {
}
const ContactDetails = ({ action, contact }: Props) => {
- const { keyboardShown } = useKeyboard()
const { t } = useTranslation()
- const homeNav = useNavigation()
const addressBookNav = useNavigation()
const route = useRoute()
- const { backgroundStyle } = useOpacity('surface', keyboardShown ? 0.85 : 0.4)
+ const { bottom } = useSafeAreaInsets()
const { addContact, editContact, deleteContact } = useAccountStorage()
const [nickname, setNickname] = useState(contact?.alias || '')
const [address, setAddress] = useState('')
const nicknameInput = useRef(null)
- const { blueBright500 } = useColors()
+ const colors = useColors()
const { scannedAddress, setScannedAddress } = useAppStorage()
const spacing = useSpacing()
const { showOKCancelAlert } = useAlert()
@@ -101,10 +100,6 @@ const ContactDetails = ({ action, contact }: Props) => {
}
}, [debouncedAddress, handleDomainAddress, nickname])
- const onRequestClose = useCallback(() => {
- homeNav.goBack()
- }, [homeNav])
-
const isAddingContact = useMemo(() => action === 'add', [action])
const isEditingContact = useMemo(() => action === 'edit', [action])
@@ -136,7 +131,7 @@ const ContactDetails = ({ action, contact }: Props) => {
const handleSaveNewContact = useCallback(() => {
if (!contact) return
editContact(contact.address, {
- address,
+ address: solAddressToHelium(address),
alias: nickname,
netType: accountNetType(address),
})
@@ -174,167 +169,171 @@ const ContactDetails = ({ action, contact }: Props) => {
}, [address])
return (
-
-
+
+
-
-
- {isAddingContact
- ? t('addNewContact.title')
- : t('editContact.title')}
-
-
-
+
+
+
+
+ {addressIsValid && (
+
+ )}
+ {!!nickname && (
+
+ {nickname}
+
+ )}
+
+
+
+ {t('addNewContact.address.title', {
+ network: 'Solana',
+ })}
+
+
+
+
+
+
+
+
+ {t('addNewContact.nickname.title')}
+
+ {!!nickname && }
+
+
+
+
+
+
+
+
+
+
+
-
- {addressIsValid && (
-
- )}
- {!!nickname && (
-
- {nickname}
-
- )}
-
-
-
-
-
- {t('addNewContact.address.title', {
- network: 'Solana',
- })}
-
-
-
-
-
- {t('addNewContact.nickname.title')}
- {!!nickname && }
-
-
-
-
-
-
-
-
-
-
-
+
+
)
}
diff --git a/src/features/addressBook/ContactsList.tsx b/src/features/addressBook/ContactsList.tsx
index 0ab160665..3b24231a3 100644
--- a/src/features/addressBook/ContactsList.tsx
+++ b/src/features/addressBook/ContactsList.tsx
@@ -8,11 +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 { CSAccount } from '../../storage/cloudStorage'
+import { useSpacing } from '@config/theme/themeHooks'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { CSAccount } from '@config/storage/cloudStorage'
type Props = {
onAddNew: () => void
@@ -34,6 +37,8 @@ const ContactsList = ({
useAccountStorage()
const { t } = useTranslation()
+ const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
const [searchTerm, setSearchTerm] = useState('')
const handleContactPressed = useCallback(
(item: CSAccount) => {
@@ -42,56 +47,6 @@ const ContactsList = ({
[handleContactSelected],
)
- const renderFlatlistItem = useCallback(
- // eslint-disable-next-line react/no-unused-prop-types
- ({ item: account }: { item: CSAccount; index: number }) => {
- return (
-
- )
- },
- [address, handleContactPressed],
- )
-
- const header = useMemo(() => {
- return (
-
-
-
-
-
- {t('addressBook.addNext')}
-
-
-
- )
- }, [onAddNew, searchTerm, t])
-
- const keyExtractor = useCallback((item: CSAccount) => {
- return item.address
- }, [])
-
const allContacts = useMemo(() => {
const contacts = contactsForNetType()
@@ -142,6 +97,74 @@ const ContactsList = ({
searchTerm,
])
+ const renderFlatlistItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ item: account, index }: { item: CSAccount; index: number }) => {
+ const borderTopStartRadius = index === 0 ? '2xl' : undefined
+ const borderTopEndRadius = index === 0 ? '2xl' : undefined
+ const borderBottomStartRadius =
+ data.length - 1 === index ? '4xl' : undefined
+ const borderBottomEndRadius =
+ data.length - 1 === index ? '4xl' : undefined
+
+ return (
+
+ )
+ },
+ [address, handleContactPressed, data],
+ )
+
+ const header = useMemo(() => {
+ return (
+
+
+
+
+
+ {t('addressBook.addNext')}
+
+
+
+ )
+ }, [onAddNew, searchTerm, t])
+
+ const keyExtractor = useCallback((item: CSAccount) => {
+ return item.address
+ }, [])
+
+ const contentContainerStyle = useMemo(() => {
+ return {
+ padding: spacing['5'],
+ paddingBottom: NavBarHeight + bottom,
+ }
+ }, [spacing, bottom])
+
if (insideBottomSheet) {
return (
)
}
@@ -159,6 +183,7 @@ const ContactsList = ({
data={data}
renderItem={renderFlatlistItem}
keyExtractor={keyExtractor}
+ contentContainerStyle={contentContainerStyle}
/>
)
}
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/BrowserListItem.tsx b/src/features/browser/BrowserListItem.tsx
index 3244e82ea..c5a4b6501 100644
--- a/src/features/browser/BrowserListItem.tsx
+++ b/src/features/browser/BrowserListItem.tsx
@@ -18,15 +18,17 @@ const BrowserListItem = ({
}: ActivityListItemProps) => {
return (
-
- {url}
+
+
+ {url}
+
)
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 4dffd4812..b98f0ef58 100644
--- a/src/features/browser/BrowserScreen.tsx
+++ b/src/features/browser/BrowserScreen.tsx
@@ -1,5 +1,4 @@
import React, { useCallback, useMemo, useRef, useState } from 'react'
-import { Edge, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useAnimatedStyle, withTiming } from 'react-native-reanimated'
import {
NativeSyntheticEvent,
@@ -7,34 +6,32 @@ 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 SafeAreaBox from '@components/SafeAreaBox'
import TextInput from '@components/TextInput'
import Box from '@components/Box'
import { ReAnimatedBox } from '@components/AnimatedBox'
-import { useColors, 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 = () => {
const DEFAULT_URL = ''
const { cluster } = useSolana()
- const edges = useMemo(() => ['top'] as Edge[], [])
const [inputFocused, setInputFocused] = useState(false)
const spacing = useSpacing()
const textInputRef = useRef(null)
- const { top } = useSafeAreaInsets()
const colors = useColors()
+ const { alphaColor } = useOpacity('primaryBackground', 0.8)
const navigation = useNavigation()
const { favorites, recents, addRecent } = useBrowser()
const { t } = useTranslation()
@@ -51,7 +48,12 @@ const BrowserScreen = () => {
const sections = [
{
title: t('browserScreen.topPicks'),
- data: recommendedDappsData ? recommendedDappsData[cluster] : [],
+ data: recommendedDappsData
+ ? [
+ 'https://anza-xyz.github.io/wallet-adapter/example/',
+ ...recommendedDappsData[cluster],
+ ]
+ : [],
},
{
title: t('browserScreen.myFavorites'),
@@ -79,7 +81,7 @@ const BrowserScreen = () => {
if (inputFocused) {
// Animate margin end
return {
- marginEnd: withTiming(spacing.xxl, {
+ marginEnd: withTiming(spacing[12], {
duration: 100,
}),
}
@@ -115,14 +117,13 @@ const BrowserScreen = () => {
const BrowserHeader = useCallback(() => {
return (
{
TrailingIcon={inputFocused ? CloseCircle : undefined}
onTrailingIconPress={onClearPressed}
TrailingIconOptions={{
- paddingStart: 's',
+ paddingStart: '2',
}}
+ textColor="primaryBackground"
textInputProps={{
placeholder: 'Search or type URL',
autoFocus: false,
@@ -150,17 +152,18 @@ const BrowserScreen = () => {
autoCorrect: false,
textAlign: inputFocused ? 'left' : 'center',
keyboardAppearance: 'dark',
+ placeholderTextColor: alphaColor,
}}
/>
{inputFocused && (
-
+
{t('generic.cancel')}
@@ -179,6 +182,7 @@ const BrowserScreen = () => {
colors,
spacing,
onSubmitEditing,
+ alphaColor,
])
const renderSectionHeader = useCallback(({ section: { title } }) => {
@@ -187,13 +191,13 @@ const BrowserScreen = () => {
-
+
{title}
@@ -222,7 +226,7 @@ const BrowserScreen = () => {
borderBottomStartRadius={lastItem ? 'xl' : undefined}
borderBottomEndRadius={lastItem ? 'xl' : undefined}
hasDivider={!lastItem || (firstItem && section.data?.length !== 1)}
- marginHorizontal="m"
+ marginHorizontal="4"
url={item}
onPress={handleBrowserListItemPress(item)}
/>
@@ -240,12 +244,12 @@ const BrowserScreen = () => {
return (
-
+
{title === t('browserScreen.myFavorites')
? t('browserScreen.myFavoritesEmpty')
: t('browserScreen.recentlyVisitedEmpty')}
@@ -258,37 +262,27 @@ const BrowserScreen = () => {
const contentContainer = useMemo(
() => ({
- paddingTop: spacing.m,
+ paddingTop: spacing['6xl'],
+ backgroundColor: colors.primaryBackground,
+ flex: 1,
}),
- [spacing.m],
+ [spacing, colors],
)
const keyExtractor = useCallback((item, index) => item + index, [])
return (
-
-
-
-
-
-
-
-
+
)
}
diff --git a/src/features/browser/BrowserWebViewScreen.tsx b/src/features/browser/BrowserWebViewScreen.tsx
index 46aad86e8..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 { 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'
@@ -67,6 +67,7 @@ const BrowserWebViewScreen = () => {
const isAndroid = useMemo(() => Platform.OS === 'android', [])
const spacing = useSpacing()
const [isScriptInjected, setIsScriptInjected] = useState(false)
+ const { ...colors } = useColors()
const isFavorite = useMemo(() => {
return favorites.some((favorite) => favorite === currentUrl)
@@ -421,30 +422,31 @@ const BrowserWebViewScreen = () => {
const BrowserHeader = useCallback(() => {
return (
-
+
{currentUrl}
-
-
+
+
)
- }, [currentUrl, closeModal, spacing])
+ }, [currentUrl, closeModal, spacing, colors])
const onBack = useCallback(() => {
webview.current?.goBack()
@@ -464,23 +466,27 @@ const BrowserWebViewScreen = () => {
const BrowserFooter = useCallback(() => {
return (
-
+
-
+
-
+
{isFavorite ? (
-
+
) : (
-
+
)}
@@ -491,13 +497,13 @@ const BrowserWebViewScreen = () => {
)
- }, [onBack, onForward, isFavorite, onFavorite, onRefresh])
+ }, [onBack, onForward, isFavorite, onFavorite, onRefresh, colors])
return (
{}}>
{
= [
titleKey: 'defiTutorial.slides.0.title',
bodyKey: 'defiTutorial.slides.0.body',
image: require('@assets/images/defiSlide1.png'),
- imageVerticalOffset: 'n_xxl',
+ imageVerticalOffset: '-12',
},
{
titleKey: 'defiTutorial.slides.1.title',
bodyKey: 'defiTutorial.slides.1.body',
image: require('@assets/images/defiSlide2.png'),
- imageVerticalOffset: 'n_xxl',
+ imageVerticalOffset: '-12',
},
{
titleKey: 'defiTutorial.slides.2.title',
bodyKey: 'defiTutorial.slides.2.body',
image: require('@assets/images/defiSlide3.png'),
- imageVerticalOffset: 'n_xxl',
+ imageVerticalOffset: '-12',
},
{
titleKey: 'defiTutorial.slides.3.title',
bodyKey: 'defiTutorial.slides.3.body',
image: require('@assets/images/defiSlide4.png'),
- imageVerticalOffset: 'n_xxl',
+ imageVerticalOffset: '-12',
},
]
const DAppTutorial = () => {
@@ -87,18 +88,18 @@ const DAppTutorial = () => {
width={wp(50)}
/>
{t(item.titleKey)}
@@ -112,35 +113,28 @@ const DAppTutorial = () => {
width: 6,
height: 6,
borderRadius: 3,
- marginHorizontal: spacing.s,
- backgroundColor: colors.white,
+ marginHorizontal: spacing['0.5'],
+ backgroundColor: colors.primaryText,
}),
- [colors.white, spacing.s],
+ [colors, spacing],
)
return (
-
-
-
- {t('defiTutorial.title')}
-
-
-
+
+
+
+
{
/>
diff --git a/src/features/burn/BurnScreen.tsx b/src/features/burn/BurnScreen.tsx
index 74e7cac45..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,35 +34,35 @@ 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'
+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 { HomeNavigationProp, HomeStackParamList } from '../home/homeTypes'
import PaymentItem from '../payment/PaymentItem'
import PaymentSubmit from '../payment/PaymentSubmit'
import PaymentSummary from '../payment/PaymentSummary'
const FEE = new BN(TXN_FEE_IN_SOL)
-type Route = RouteProp
+type Route = RouteProp
const BurnScreen = () => {
const route = useRoute()
const {
@@ -77,12 +72,12 @@ const BurnScreen = () => {
setCurrentAccount,
defaultAccountAddress,
} = useAccountStorage()
- const { top } = useSafeAreaInsets()
- const navigation = useNavigation()
+ const spacing = useSpacing()
+ const { top, bottom } = useSafeAreaInsets()
+ const navigation = useNavigation()
const { t } = useTranslation()
const { primaryText } = useColors()
- const hitSlop = useHitSlop('l')
- const accountSelectorRef = useRef(null)
+ const hitSlop = useHitSlop('6')
const { submitDelegateDataCredits } = useSubmitTxn()
const addressBookRef = useRef(null)
const { networkTokensToDc } = useBalance()
@@ -108,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(
@@ -117,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)
@@ -136,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
@@ -298,237 +296,208 @@ const BurnScreen = () => {
if (!amountBalance) return null
return (
-
-
+
-
-
-
+
+
+
+
+
+
+ {t(isDelegate ? 'delegate.title' : 'burn.title')}
+
+
+
+
+
+
+
+
+
+ {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(isDelegate ? 'delegate.title' : 'burn.title')}
+ {t('burn.amount')}
+
+
+ {amountBalance.toString()}
-
-
-
-
+ {t('payment.fee', {
+ value: humanReadable(FEE, 9),
+ })}
+
-
- 1}
- address={currentAccount?.address}
- onPress={handleShowAccounts}
- showBubbleArrow
- marginHorizontal="l"
- marginBottom="xs"
+
-
+
+ {t('burn.equivalent')}
+
+
+ {amountInDc?.toString()}
+
- {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}
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
+ >
+ )}
+
+ {submitError && (
+
+
+ {submitError}
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ >
)
}
diff --git a/src/features/collectables/CollectablesNavigator.tsx b/src/features/collectables/CollectablesNavigator.tsx
deleted file mode 100644
index dffa4fc61..000000000
--- a/src/features/collectables/CollectablesNavigator.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import {
- StackNavigationOptions,
- createStackNavigator,
-} from '@react-navigation/stack'
-import React, { memo } from 'react'
-import AddNewContact from '../addressBook/AddNewContact'
-import AddressBookNavigator from '../addressBook/AddressBookNavigator'
-import AddressQrScanner from '../addressBook/AddressQrScanner'
-import OnboardingNav from '../hotspot-onboarding/OnboardingNav'
-import PaymentQrScanner from '../payment/PaymentQrScanner'
-import PaymentScreen from '../payment/PaymentScreen'
-import AntennaSetupScreen from './AntennaSetupScreen'
-import ClaimAllRewardsScreen from './ClaimAllRewardsScreen'
-import ClaimRewardsScreen from './ClaimRewardsScreen'
-import ClaimingRewardsScreen from './ClaimingRewardsScreen'
-import CollectablesTopTabs from './CollectablesTopTabs'
-import CollectionScreen from './CollectionScreen'
-import NftDetailsScreen from './NftDetailsScreen'
-import NftMetadataScreen from './NftMetadataScreen'
-import SettingUpAntennaScreen from './SettingUpAntennaScreen'
-import TransferCollectableScreen from './TransferCollectableScreen'
-import TransferCompleteScreen from './TransferCompleteScreen'
-import HotspotMapScreen from './HotspotMapScreen'
-import AssertLocationScreen from './AssertLocationScreen'
-import ChangeRewardsRecipientScreen from './ChangeRewardsRecipientScreen'
-
-const CollectablesStack = createStackNavigator()
-
-const screenOptions: StackNavigationOptions = {
- headerShown: false,
-}
-
-const CollectablesStackScreen = () => {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default memo(CollectablesStackScreen)
diff --git a/src/features/collectables/CollectablesScreen.tsx b/src/features/collectables/CollectablesScreen.tsx
deleted file mode 100644
index a5ffb07a1..000000000
--- a/src/features/collectables/CollectablesScreen.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { useCallback, useMemo, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import { Edge } from 'react-native-safe-area-context'
-import { SvgProps } from 'react-native-svg'
-import NFT from '@assets/images/nft.svg'
-import Hotspot from '@assets/images/hotspot.svg'
-import TabBar from '@components/TabBar'
-import Text from '@components/Text'
-import SafeAreaBox from '@components/SafeAreaBox'
-import { DelayedFadeIn } from '@components/FadeInOut'
-import globalStyles from '@theme/globalStyles'
-import { ReAnimatedBox } from '@components/AnimatedBox'
-import AccountCollectablesList from './NftList'
-import AccountHotspotsList from './HotspotList'
-
-const CollectablesScreen = () => {
- const { t } = useTranslation()
- const [selectedItem, setSelectedItem] = useState('hotspots')
- const safeEdges = useMemo(() => ['top'] as Edge[], [])
-
- const handleItemSelected = useCallback((item: string) => {
- setSelectedItem(item)
- }, [])
-
- const tabData = useMemo((): Array<{
- value: string
- title: string
- Icon: React.FC
- iconPosition: 'top' | 'leading' | undefined
- }> => {
- return [
- {
- value: 'hotspots',
- title: t('collectablesScreen.hotspots.title'),
- Icon: Hotspot,
- iconPosition: 'leading',
- },
- {
- value: 'collectables',
- title: t('collectablesScreen.nfts.title'),
- Icon: NFT,
- iconPosition: 'leading',
- },
- ]
- }, [t])
-
- return (
-
-
-
- {t('collectablesScreen.title')}
-
-
-
- {selectedItem === tabData[0].value && }
- {selectedItem === tabData[1].value && }
-
-
- )
-}
-
-export default CollectablesScreen
diff --git a/src/features/collectables/CollectablesTopTabs.tsx b/src/features/collectables/CollectablesTopTabs.tsx
deleted file mode 100644
index 394cf8c5e..000000000
--- a/src/features/collectables/CollectablesTopTabs.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import React, { FC, useCallback, useMemo } from 'react'
-import {
- createMaterialTopTabNavigator,
- MaterialTopTabNavigationOptions,
-} from '@react-navigation/material-top-tabs'
-import { useTranslation } from 'react-i18next'
-import { RouteProp } from '@react-navigation/native'
-import { SvgProps } from 'react-native-svg'
-import Hotspot from '@assets/images/hotspot.svg'
-import NFT from '@assets/images/nft.svg'
-import Box from '@components/Box'
-import { Font } from '@theme/theme'
-import { useColors } from '@theme/themeHooks'
-import Text from '@components/Text'
-import HotspotList from './HotspotList'
-import NftList from './NftList'
-import SafeAreaBox from '../../components/SafeAreaBox'
-
-const Tab = createMaterialTopTabNavigator()
-
-export type CollectablesTabParamList = {
- Hotspots: undefined
- NFTs: undefined
-}
-
-const CollectablesTopTabs = () => {
- const { t } = useTranslation()
- const colors = useColors()
- const edges = useMemo(() => ['top'] as const, [])
-
- const screenOpts = useCallback(
- ({ route }: { route: RouteProp }) =>
- ({
- lazy: true,
- headerShown: false,
- tabBarLabelStyle: {
- fontFamily: Font.medium,
- fontSize: 20,
- textTransform: 'none',
- },
- tabBarShowIcon: true,
- tabBarStyle: {
- backgroundColor: colors.primaryBackground,
- width: '100%',
- },
- tabBarContentContainerStyle: {
- borderBottomColor: colors.secondaryText,
- borderBottomWidth: 1,
- justifyContent: 'center',
- },
- tabBarIndicatorStyle: {
- backgroundColor: colors.primaryText,
- height: 3,
- position: undefined,
- },
- tabBarIndicatorContainerStyle: {
- justifyContent: 'flex-end',
- },
- tabBarItemStyle: {
- flexDirection: 'row',
- flex: 1,
- },
- tabBarIcon: ({ focused }) => {
- const color = focused ? colors.primaryText : colors.secondaryText
- let Icon: FC | null = null
- switch (route.name) {
- case 'Hotspots':
- Icon = Hotspot
- break
- case 'NFTs':
- Icon = NFT
- break
- }
- if (!Icon) return null
-
- return (
-
-
-
- )
- },
- tabBarActiveTintColor: colors.primaryText,
- tabBarInactiveTintColor: colors.secondaryText,
- title: t(`collectablesScreen.${route.name.toLowerCase()}.title`),
- } as MaterialTopTabNavigationOptions),
-
- [colors.primaryBackground, colors.primaryText, colors.secondaryText, t],
- )
-
- return (
-
-
- {t('collectablesScreen.title')}
-
- {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
- {/* @ts-ignore This warning is a bug with @react-navigation */}
-
-
-
-
-
- )
-}
-
-export default CollectablesTopTabs
diff --git a/src/features/collectables/CollectionItem.tsx b/src/features/collectables/CollectionItem.tsx
new file mode 100644
index 000000000..58a446fa2
--- /dev/null
+++ b/src/features/collectables/CollectionItem.tsx
@@ -0,0 +1,86 @@
+import Box from '@components/Box'
+import Text from '@components/Text'
+import { BoxProps } from '@shopify/restyle'
+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/svgs/visibilityOff.svg'
+import { collectables as collectablesSli } from '@store/slices/collectablesSlice'
+
+export type Collection = {
+ id: string
+ name: string
+ image: string
+ description: string
+ count: number
+}
+
+type CollectionItemProps = {
+ collection: Collection
+ initalEnabled: boolean
+}
+const CollectionItem = ({
+ collection,
+ initalEnabled,
+ ...rest
+}: CollectionItemProps & BoxProps) => {
+ const spacing = useSpacing()
+ const [approved, setApproved] = useState(initalEnabled)
+ const dispatch = useDispatch()
+ const colors = useColors()
+
+ const onApprove = useCallback(
+ (id: string) => (a: boolean) => {
+ setApproved(a)
+ dispatch(
+ collectablesSli.actions.toggleApprovedCollection({
+ collection: id,
+ }),
+ )
+ },
+ [dispatch],
+ )
+
+ return (
+
+ {approved ? (
+
+ ) : (
+
+
+
+ )}
+
+
+ {collection.name}
+
+
+ {collection.count}
+
+
+
+
+
+
+ )
+}
+
+export default CollectionItem
diff --git a/src/features/collectables/CollectionScreen.tsx b/src/features/collectables/CollectionScreen.tsx
index 38b69931f..9b3a1ef3c 100644
--- a/src/features/collectables/CollectionScreen.tsx
+++ b/src/features/collectables/CollectionScreen.tsx
@@ -8,8 +8,9 @@ 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,
CollectableStackParamList,
@@ -27,7 +28,7 @@ const CollectionScreen = () => {
const navigation = useNavigation()
const COLLECTABLE_HEIGHT = Dimensions.get('window').width / 2
const collectables = route.params.collection
- const { lm: borderRadius } = useBorderRadii()
+ const borderRadii = useBorderRadii()
const { triggerImpact } = useHaptic()
const handleNavigateToCollectable = useCallback(
@@ -43,8 +44,6 @@ const CollectionScreen = () => {
const renderCollectable = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ item }: { item: Collectable }) => {
- const { json } = item
-
return (
{
exiting={FadeOut}
>
handleNavigateToCollectable(item)}
>
)
},
- [COLLECTABLE_HEIGHT, borderRadius, handleNavigateToCollectable],
+ [COLLECTABLE_HEIGHT, borderRadii, handleNavigateToCollectable],
)
const keyExtractor = useCallback((item: Collectable) => item.id, [])
return (
-
-
+
-
-
-
+
+
+
+
+
)
}
diff --git a/src/features/collectables/HotspotCompressedListItem.tsx b/src/features/collectables/HotspotCompressedListItem.tsx
deleted file mode 100644
index bdc7ae2e4..000000000
--- a/src/features/collectables/HotspotCompressedListItem.tsx
+++ /dev/null
@@ -1,247 +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('flamenco', 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 5558a9516..000000000
--- a/src/features/collectables/HotspotList.tsx
+++ /dev/null
@@ -1,304 +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 } 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 { 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 {
- 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="white"
- fontSize={14}
- onPress={handleNavigateToMap}
- />
-
- }
- title={t('collectablesScreen.hotspots.connect')}
- titleColor="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 (
- <>
-
- }
- renderItem={renderCollectable}
- ListEmptyComponent={renderEmptyComponent}
- onEndReachedThreshold={0.001}
- onEndReached={handleOnEndReached}
- keyExtractor={keyExtractor}
- ListFooterComponent={Footer}
- />
-
-
-
-
-
-
-
- >
- )
-}
-
-export default HotspotList
diff --git a/src/features/collectables/HotspotListItem.tsx b/src/features/collectables/HotspotListItem.tsx
deleted file mode 100644
index e0763855d..000000000
--- a/src/features/collectables/HotspotListItem.tsx
+++ /dev/null
@@ -1,165 +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/HotspotMapScreen.tsx b/src/features/collectables/HotspotMapScreen.tsx
deleted file mode 100644
index 13b290374..000000000
--- a/src/features/collectables/HotspotMapScreen.tsx
+++ /dev/null
@@ -1,588 +0,0 @@
-/* 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 { ReAnimatedBlurBox, ReAnimatedBox } from '@components/AnimatedBox'
-import Box from '@components/Box'
-import CircleLoader from '@components/CircleLoader'
-import FabButton from '@components/FabButton'
-import { DelayedFadeIn } from '@components/FadeInOut'
-import SafeAreaBox from '@components/SafeAreaBox'
-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,
- BottomSheetScrollView,
-} from '@gorhom/bottom-sheet'
-import {
- decodeEntityKey,
- init,
- iotInfoKey,
- keyToAssetForAsset,
- mobileInfoKey,
-} from '@helium/helium-entity-manager-sdk'
-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 { 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 { Edge } from 'react-native-safe-area-context'
-import { useSolana } from '../../solana/SolanaProvider'
-import { HotspotWithPendingRewards } from '../../types/solana'
-import { HotspotMapHotspotDetails } from './HotspotMapHotspotDetails'
-import { HotspotMapLegend } from './HotspotMapLegend'
-import {
- CollectableNavigationProp,
- CollectableStackParamList,
-} from './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()
- const route = useRoute()
- const bottomSheetStyle = useBackgroundStyle('surfaceSecondary')
- const navigation = useNavigation()
- const colors = useColors()
- const mapRef = useRef(null)
- const cameraRef = useRef(null)
- const bottomSheetRef = useRef(null)
- const [bottomSheetHeight, setBottomSheetHeight] = useState(0)
- const [bottomSheetSnapIndex, setBottomSheetSnapIndex] = useState(-1)
- const [backEdges] = [['top']] as Edge[][]
- 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',
- )
- const [loadingInfos, setLoadingInfos] = useState(false)
- const [hexInfoBuckets, setHexInfoBuckets] = useState<{
- [key: string]: IotHotspotInfoV0[] | MobileHotspotInfoV0[]
- }>({})
- const [activeHex, setActiveHex] = useState()
- 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])
-
- // - fetch all hotspots
- useEffect(() => {
- if (!loading && !onEndReached) {
- fetchAll()
- }
- }, [loading, onEndReached, fetchAll])
-
- // - fetch infos by networkType for all hotspots
- // - setUp hexInfoBuckets
- useAsync(async () => {
- if (onEndReached && anchorProvider) {
- setLoadingInfos(true)
- const hemProgram = await init(anchorProvider)
-
- const infos = (
- await Promise.all(
- chunks(hotspots, 100).map(async (chunk) => {
- const keyToAssetKeys = chunk.map((h) =>
- keyToAssetForAsset(toAsset(h)),
- )
-
- const ktaAccs = await getCachedKeyToAssets(
- hemProgram,
- keyToAssetKeys,
- )
-
- const entityKeys = ktaAccs
- .map((kta) => {
- return decodeEntityKey(kta.entityKey, kta.keySerialization)
- })
- .filter(truthy)
-
- const infoKeys = entityKeys.map((ek) => {
- const keys = {
- IOT: iotInfoKey(IOT_CONFIG_KEY, ek)[0],
- MOBILE: mobileInfoKey(MOBILE_CONFIG_KEY, ek)[0],
- }
-
- return keys[networkType]
- })
-
- if (networkType === 'IOT') {
- return getCachedIotInfos(hemProgram, infoKeys)
- }
-
- if (networkType === 'MOBILE') {
- return getCachedMobileInfos(hemProgram, infoKeys)
- }
- }),
- )
- ).flat()
-
- const infoBuckets = infos
- .filter((info) => info && truthy(info.location))
- .reduce(
- (acc, info) => ({
- ...acc,
- ...(info?.location
- ? {
- [info.location.toString()]: [
- ...(acc[info.location.toString()] || []),
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- info as any,
- ],
- }
- : {}),
- }),
- {} as {
- [key: string]: IotHotspotInfoV0[] | MobileHotspotInfoV0[]
- },
- )
-
- setHexInfoBuckets(infoBuckets)
- setLoadingInfos(false)
- }
- }, [
- onEndReached,
- anchorProvider,
- networkType,
- hotspots,
- setLoadingInfos,
- setHexInfoBuckets,
- ])
-
- useAsync(async () => {
- // if hotspot is provided, check if it's IOT or MOBILE
- // scope networkType to the hotspot's network type
- if (hotspot) {
- if (onEndReached && !loadingInfos && anchorProvider) {
- const [hex] = Object.entries(hexInfoBuckets).find(([_, infos]) => {
- return infos.some((info) => info?.asset.toBase58() === hotspot.id)
- }) || [DEFAULT_HEX]
-
- setActiveHex(hex)
- if (hex !== DEFAULT_HEX) {
- setActiveHotspotIndex(
- hexInfoBuckets[hex].findIndex(
- (info) => info.asset.toBase58() === hotspot.id,
- ),
- )
- }
- }
- }
- }, [anchorProvider, onEndReached, loadingInfos, hotspot])
-
- // - show bottom sheet when activeHex is set
- useEffect(() => {
- if (activeHex || legendVisible) {
- bottomSheetRef.current?.present()
- } else {
- bottomSheetRef.current?.dismiss()
- }
- }, [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],
- )
-
- const activeHexItem = useMemo(() => {
- if (!loadingInfos && activeHex) {
- if (activeHex === DEFAULT_HEX && hotspot) {
- return {
- hotspot,
- info: undefined,
- }
- }
-
- const info = (hexInfoBuckets[activeHex] || [])[activeHotspotIndex]
- if (info) {
- return {
- hotspot: hotspots.find(
- (h) => h.id === info.asset.toBase58(),
- ) as HotspotWithPendingRewards,
- info,
- }
- }
- }
- }, [
- loadingInfos,
- hexInfoBuckets,
- activeHex,
- activeHotspotIndex,
- hotspots,
- hotspot,
- ])
-
- const isLoading = useMemo(
- () => loading || !onEndReached || loadingInfos,
- [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 handleLegendPress = useCallback(() => {
- setLegendVisible(true)
- }, [setLegendVisible])
-
- const handleToggleNetwork = useCallback(() => {
- setNetworkType(networkType === 'IOT' ? 'MOBILE' : 'IOT')
- 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],
- )
-
- return (
-
-
-
-
-
-
-
-
-
-
- navigation.goBack()}
- >
-
-
- {t('collectablesScreen.hotspots.map.back')}
-
-
-
-
-
-
-
-
- {t('collectablesScreen.hotspots.map.type', {
- type: networkType,
- })}
-
-
-
-
-
-
-
-
-
-
- setActiveHex(undefined)}
- onChange={(idx) => setBottomSheetSnapIndex(idx)}
- >
-
-
- setBottomSheetHeight(e.nativeEvent.layout.height)
- }
- >
- {legendVisible && }
- {activeHexItem && (
-
- )}
-
-
-
-
-
-
- )
-}
-
-export default HotspotMapScreen
diff --git a/src/features/collectables/ManageCollectables.tsx b/src/features/collectables/ManageCollectables.tsx
new file mode 100644
index 000000000..798a5d550
--- /dev/null
+++ b/src/features/collectables/ManageCollectables.tsx
@@ -0,0 +1,129 @@
+import BackScreen from '@components/BackScreen'
+import ScrollBox from '@components/ScrollBox'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import useCollectables from '@hooks/useCollectables'
+import { RootState } from '@store/rootReducer'
+import { useColors } from '@config/theme/themeHooks'
+import { heliumNFTs } from '@utils/solanaUtils'
+import React, { useCallback } from 'react'
+import { useAsync } from 'react-async-hook'
+import { FlatList, RefreshControl } from 'react-native'
+import { useSelector } from 'react-redux'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { useTranslation } from 'react-i18next'
+import CollectionItem, { Collection } from './CollectionItem'
+
+const ManageCollectables = () => {
+ const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+ const colors = useColors()
+ const { fetchAllCollectablesByGroup } = useCollectables()
+ const approvedCollections = useSelector(
+ (state: RootState) => state.collectables.approvedCollections,
+ )
+
+ const fetchSortedCollectables = useCallback(async () => {
+ const collectables = await fetchAllCollectablesByGroup()
+
+ const collectionItems: Collection[] = Object.keys(collectables).map(
+ (key) => {
+ const collectable = collectables[key][0]
+
+ return {
+ id: key,
+ name: collectable.content.metadata?.name || '',
+ image: collectable.content?.files[0]?.uri,
+ description: collectable.content.metadata?.description || '',
+ count: collectables[key].length,
+ }
+ },
+ )
+
+ const approved = approvedCollections || heliumNFTs()
+
+ // sort by approved collections to non-approved collections
+ collectionItems.sort((a, b) => {
+ if (approved.includes(a.id) && !approved.includes(b.id)) {
+ return -1
+ }
+ if (!approved.includes(a.id) && approved.includes(b.id)) {
+ return 1
+ }
+ return 0
+ })
+
+ return collectionItems
+ }, [fetchAllCollectablesByGroup, approvedCollections])
+
+ const {
+ result: collectables,
+ execute,
+ loading,
+ } = useAsync(async () => {
+ return fetchSortedCollectables()
+ }, [])
+
+ const renderItem = useCallback(
+ // eslint-disable-next-line react/no-unused-prop-types
+ ({ index, item: collection }: { index: number; item: Collection }) => {
+ if (!collectables) return null
+
+ const isFirst = index === 0
+ const isLast = index === collectables?.length - 1
+ const borderTopStartRadius = isFirst ? 'xl' : 'none'
+ const borderTopEndRadius = isFirst ? 'xl' : 'none'
+ const borderBottomStartRadius = isLast ? 'xl' : 'none'
+ const borderBottomEndRadius = isLast ? 'xl' : 'none'
+
+ const approved = approvedCollections || heliumNFTs()
+
+ return (
+
+ )
+ },
+ [approvedCollections, collectables],
+ )
+
+ const keyExtractor = useCallback((item: Collection) => {
+ return item.id
+ }, [])
+
+ return (
+
+ }
+ >
+
+
+
+
+ )
+}
+
+export default ManageCollectables
diff --git a/src/features/collectables/NftDetailsScreen.tsx b/src/features/collectables/NftDetailsScreen.tsx
index 4bb159ce1..ba24b1028 100644
--- a/src/features/collectables/NftDetailsScreen.tsx
+++ b/src/features/collectables/NftDetailsScreen.tsx
@@ -1,40 +1,43 @@
import React, { useCallback, useMemo, memo } from 'react'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { ScrollView } from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import 'text-encoding-polyfill'
import { useTranslation } from 'react-i18next'
-import InfoIcon from '@assets/images/info.svg'
-import ArrowRight from '@assets/images/arrowRight.svg'
-import SafeAreaBox from '@components/SafeAreaBox'
+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 ButtonPressable from '@components/ButtonPressable'
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 { ww } from '../../utils/layout'
+import ScrollBox from '@components/ScrollBox'
import {
- CollectableNavigationProp,
- CollectableStackParamList,
-} from './collectablesTypes'
+ WalletNavigationProp,
+ WalletStackParamList,
+} from '@services/WalletService/pages/WalletPage'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import ButtonPressable from '@components/ButtonPressable'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import NftMetadata from './NftMetadata'
+import { ww } from '../../utils/layout'
+import { CompressedNFT } from '../../types/solana'
-type Route = RouteProp
+type Route = RouteProp
const NftDetailsScreen = () => {
const route = useRoute()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const COLLECTABLE_HEIGHT = ww
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
- const backEdges = useMemo(() => ['top'] as Edge[], [])
+ const { bottom } = useSafeAreaInsets()
+ const { editAvatar } = useAccountStorage()
const { t } = useTranslation()
- const { collectable } = route.params
- const { json } = collectable
+ const { collectable }: { collectable: CompressedNFT } = route.params
+ const { content } = collectable
const spacing = useSpacing()
@@ -44,101 +47,149 @@ const NftDetailsScreen = () => {
})
}, [collectable, navigation])
- const handleInfoPress = useCallback(() => {
- if (json) {
- navigation.push('NftMetadataScreen', {
- metadata: json,
- })
- }
- }, [navigation, json])
+ const imageUri = useMemo(() => {
+ return content?.files?.[0]?.uri
+ }, [content])
+
+ const updateAvatar = useCallback(async () => {
+ await editAvatar(imageUri)
+ }, [imageUri, editAvatar])
+
+ const TransferButton = useCallback(() => {
+ return (
+
+
+
+ {t('collectablesScreen.transfer')}
+
+
+ )
+ }, [t, handleSend])
+
+ const AvatarButton = useCallback(() => {
+ return (
+
+
+
+ {t('collectablesScreen.nfts.setAsAvatar')}
+
+
+ )
+ }, [t, updateAvatar])
- const backgroundImageUri = useMemo(() => {
- return json?.image
- }, [json])
+ const isNFT = useMemo(() => {
+ return ['programmablenft', 'v1_nft', 'v2_nft', 'legacy_nft'].includes(
+ collectable.interface?.toLowerCase(),
+ )
+ }, [collectable])
return (
-
-
-
- {json && (
+
+
+
+
+ {content && (
+
+
+
+ )}
+
+ {content?.metadata?.name}
+
+
+ {content?.metadata?.description ||
+ t('collectables.noDescription')}
+
+
+ {isNFT && (
+
+
+
+
+ )}
+
-
+
- )}
-
- {json?.name}
-
-
- {json?.description || t('collectables.noDescription')}
-
-
- {collectable.model === 'nft' && (
-
- }
- />
- )}
-
-
-
+
+
+
)
}
diff --git a/src/features/collectables/NftList.tsx b/src/features/collectables/NftList.tsx
index 156400ae6..e4ed8c853 100644
--- a/src/features/collectables/NftList.tsx
+++ b/src/features/collectables/NftList.tsx
@@ -1,35 +1,51 @@
-import React, { useCallback, useMemo, useEffect } from 'react'
+import React, { useCallback, useEffect, useMemo } from 'react'
import { times } from 'lodash'
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/svgs/config.svg'
+import Text from '@components/Text'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import ScrollBox from '@components/ScrollBox'
+import { useSelector } from 'react-redux'
+import { RootState } from '@store/rootReducer'
import NFTListItem, { NFTSkeleton } from './NftListItem'
-import { CollectableNavigationProp } from './collectablesTypes'
const NftList = () => {
const spacing = useSpacing()
- const navigation = useNavigation()
+ const { bottom } = useSafeAreaInsets()
+ const navigation = useNavigation()
+ const approvedCollections = useSelector(
+ (state: RootState) => state.collectables.approvedCollections,
+ )
const {
collectables,
- collectablesWithMeta,
loading: loadingCollectables,
refresh,
} = useCollectables()
const { primaryText } = useColors()
useEffect(() => {
- return navigation.addListener('focus', () => {
+ if (approvedCollections?.length > 0) {
refresh()
- })
- }, [navigation, refresh])
+ }
+ }, [refresh, approvedCollections])
const flatListItems = useMemo(() => {
- return collectablesWithMeta ? Object.keys(collectablesWithMeta) : []
- }, [collectablesWithMeta])
+ // always return an even number of items, if odd add an empty string
+ if (Object.keys(collectables || []).length % 2 === 0) {
+ return Object.keys(collectables || [])
+ }
+
+ return collectables ? Object.keys(collectables || []).concat(['']) : []
+ }, [collectables])
const renderItem = useCallback(
({
@@ -38,14 +54,17 @@ const NftList = () => {
// eslint-disable-next-line react/no-unused-prop-types
item: string
}) => {
+ if (token === '') {
+ return
+ }
return (
)
},
- [collectablesWithMeta],
+ [collectables],
)
const renderEmptyComponent = useCallback(() => {
@@ -64,22 +83,42 @@ const NftList = () => {
return null
}, [collectables, loadingCollectables])
+ const onManageNftList = useCallback(() => {
+ navigation.navigate('ManageCollectables')
+ }, [navigation])
+
+ const renderFooterComponent = useCallback(() => {
+ return (
+
+
+
+ Manage NFTs
+
+
+ )
+ }, [onManageNftList])
+
const keyExtractor = useCallback((item: string) => {
return item
}, [])
const contentContainerStyle = useMemo(
() => ({
- marginTop: spacing.m,
+ marginTop: spacing[4],
+ paddingBottom: NavBarHeight + bottom + spacing['6xl'],
+ paddingHorizontal: spacing[5],
+ gap: spacing[4],
}),
- [spacing.m],
+ [spacing, bottom],
)
return (
- {
tintColor={primaryText}
/>
}
- columnWrapperStyle={{
- flexDirection: 'row',
- }}
- contentContainerStyle={contentContainerStyle}
- renderItem={renderItem}
- ListEmptyComponent={renderEmptyComponent}
- keyExtractor={keyExtractor}
- />
+ >
+
+
)
}
diff --git a/src/features/collectables/NftListItem.tsx b/src/features/collectables/NftListItem.tsx
index a167d5ed3..a22b1af6c 100644
--- a/src/features/collectables/NftListItem.tsx
+++ b/src/features/collectables/NftListItem.tsx
@@ -5,10 +5,11 @@ import { FadeIn, FadeOut } from 'react-native-reanimated'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { useBorderRadii } from '@theme/themeHooks'
import CircleLoader from '@components/CircleLoader'
import { ReAnimatedBox } from '@components/AnimatedBox'
import useHaptic from '@hooks/useHaptic'
+import { useBorderRadii } from '@config/theme/themeHooks'
+import useLayoutWidth from '@hooks/useLayoutWidth'
import { ww } from '../../utils/layout'
import { Collectable } from '../../types/solana'
import { CollectableNavigationProp } from './collectablesTypes'
@@ -21,10 +22,11 @@ const NftListItem = ({
item: string
collectables: Collectable[]
}) => {
- const { lm } = useBorderRadii()
- const { json } = collectables[0]
+ const { content } = collectables[0]
const navigation = useNavigation()
const { triggerImpact } = useHaptic()
+ const borderRadii = useBorderRadii()
+ const [height, setHeight] = useLayoutWidth()
const handleCollectableNavigation = useCallback(
(collection: Collectable[]) => () => {
@@ -33,54 +35,52 @@ const NftListItem = ({
navigation.navigate('CollectionScreen', {
collection,
})
- } else if (json) {
+ } else if (content?.metadata) {
triggerImpact('light')
navigation.navigate('NftDetailsScreen', {
collectable: collection[0],
})
}
},
- [navigation, triggerImpact, json],
+ [navigation, triggerImpact, content],
)
return (
-
-
+
+
-
-
-
- {item}
-
-
- {collectables?.length}
-
-
-
-
+
+ {item}
+
+
+ {collectables?.length}
+
+
+
)
}
@@ -88,13 +88,13 @@ export const NFTSkeleton = () => {
return (
{
+ const { t } = useTranslation()
+
+ const Attribute = useCallback(
+ ({
+ traitType,
+ traitValue,
+ ...rest
+ }: {
+ traitType: string
+ traitValue: boolean | string | string[] | undefined
+ } & BoxProps) => {
+ return (
+
+
+ {traitType?.toUpperCase() ||
+ t('collectablesScreen.collectables.noTraitType')}
+
+
+ {stringify(traitValue) ||
+ t('collectablesScreen.collectables.noTraitValue')}
+
+
+ )
+ },
+ [t],
+ )
+
+ return (
+
+ {metadata.attributes?.map(({ trait_type, value }, index) => {
+ const isFirst = index === 0
+ const isLast = index === metadata.attributes.length - 1
+ const borderTopStartRadius = isFirst ? 'xl' : undefined
+ const borderTopEndRadius = isFirst ? 'xl' : undefined
+ const borderBottomStartRadius = isLast ? 'xl' : undefined
+ const borderBottomEndRadius = isLast ? 'xl' : undefined
+
+ return (
+
+ )
+ })}
+
+ )
+}
+
+export default NftMetadata
diff --git a/src/features/collectables/NftMetadataScreen.tsx b/src/features/collectables/NftMetadataScreen.tsx
deleted file mode 100644
index d7d283ef8..000000000
--- a/src/features/collectables/NftMetadataScreen.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import React, { useCallback } from 'react'
-import { useTranslation } from 'react-i18next'
-import { RouteProp, useRoute } from '@react-navigation/native'
-import BackScreen from '@components/BackScreen'
-import Box from '@components/Box'
-import Text from '@components/Text'
-import SafeAreaBox from '@components/SafeAreaBox'
-import { ScrollView } from 'react-native-gesture-handler'
-import { CollectableStackParamList } from './collectablesTypes'
-
-type Route = RouteProp
-
-function stringify(
- s: boolean | string | string[] | undefined,
-): string | undefined {
- if (Array.isArray(s)) {
- if (s.length === 0) {
- return 'None'
- }
- return s.join(', ')
- }
-
- return s?.toString()
-}
-
-const NftMetadataScreen = () => {
- const route = useRoute()
- const { t } = useTranslation()
- const { metadata } = route.params
-
- const renderProperty = useCallback(
- (
- traitType: string | undefined,
- traitValue: boolean | string | string[] | undefined,
- ) => (
-
-
- {traitType?.toUpperCase() ||
- t('collectablesScreen.collectables.noTraitType')}
-
-
- {stringify(traitValue) ||
- t('collectablesScreen.collectables.noTraitValue')}
-
-
- ),
- [t],
- )
-
- return (
-
-
-
-
- {t('collectablesScreen.collectables.properties')}
-
-
- {metadata.attributes?.map(({ trait_type, value }: any) =>
- renderProperty(trait_type, value),
- )}
-
-
-
-
- )
-}
-
-export default NftMetadataScreen
diff --git a/src/features/collectables/TransferCollectableScreen.tsx b/src/features/collectables/TransferCollectableScreen.tsx
index 1fb377295..30953b08a 100644
--- a/src/features/collectables/TransferCollectableScreen.tsx
+++ b/src/features/collectables/TransferCollectableScreen.tsx
@@ -1,6 +1,4 @@
-import ArrowRight from '@assets/images/arrowRight.svg'
-import InfoIcon from '@assets/images/info.svg'
-import Menu from '@assets/images/menu.svg'
+import ArrowRight from '@assets/svgs/arrowRight.svg'
import AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
@@ -11,38 +9,32 @@ import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
import { DelayedFadeIn } from '@components/FadeInOut'
import ImageBox from '@components/ImageBox'
-import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import TextInput from '@components/TextInput'
-import TextTransform from '@components/TextTransform'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js'
-import { useColors, useSpacing } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
import React, { memo, useCallback, useMemo, useRef, useState } from 'react'
-import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import {
KeyboardAvoidingView,
LogBox,
NativeSyntheticEvent,
- ScrollView,
TextInputEndEditingEventData,
} from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import 'text-encoding-polyfill'
+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/svgs/addressIcon.svg'
+import { WalletNavigationProp } from '@services/WalletService/pages/WalletPage'
+import { CSAccount } from '@config/storage/cloudStorage'
import useSubmitTxn from '../../hooks/useSubmitTxn'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { CSAccount } from '../../storage/cloudStorage'
-import { Collectable, CompressedNFT } from '../../types/solana'
import { solAddressIsValid } from '../../utils/accountUtils'
import { ww } from '../../utils/layout'
import * as Logger from '../../utils/logger'
-import { createTransferCollectableMessage } from '../../utils/solanaUtils'
-import {
- CollectableNavigationProp,
- CollectableStackParamList,
-} from './collectablesTypes'
+import { CollectableStackParamList } from './collectablesTypes'
LogBox.ignoreLogs([
'Non-serializable values were found in the navigation state',
@@ -52,11 +44,9 @@ type Route = RouteProp
const TransferCollectableScreen = () => {
const route = useRoute()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const COLLECTABLE_HEIGHT = ww
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
- const backEdges = useMemo(() => ['top'] as Edge[], [])
-
+ const { bottom } = useSafeAreaInsets()
const { t } = useTranslation()
const { collectable } = route.params
@@ -67,69 +57,22 @@ const TransferCollectableScreen = () => {
const [recipientName, setRecipientName] = useState('')
const [hasError, setHasError] = useState(false)
const [networkError, setNetworkError] = useState()
- const [hasInsufficientBalance, setHasInsufficientBalance] = useState<
- undefined | boolean
- >()
- const [solFee, setSolFee] = useState(undefined)
- const { currentAccount } = useAccountStorage()
- const { anchorProvider } = useSolana()
const addressBookRef = useRef(null)
const colors = useColors()
const [transferring, setTransferring] = useState(false)
- const compressedNFT = useMemo(
- () => collectable as CompressedNFT,
- [collectable],
- )
- const nft = useMemo(() => collectable as Collectable, [collectable])
+ const nft = useMemo(() => collectable as Asset, [collectable])
+
+ const image = useMemo(() => {
+ return nft?.content?.files?.[0]?.uri
+ }, [nft])
const metadata = useMemo(() => {
- return compressedNFT?.content?.metadata || nft?.json
- }, [compressedNFT, nft])
+ return nft?.content?.metadata
+ }, [nft])
const { submitCollectable } = useSubmitTxn()
- useAsync(async () => {
- if (!currentAccount?.solanaAddress || !anchorProvider?.connection) return
-
- const { connection } = anchorProvider
-
- try {
- const { message } = await createTransferCollectableMessage(
- anchorProvider,
- currentAccount?.solanaAddress,
- currentAccount?.address || '',
- collectable,
- currentAccount?.solanaAddress,
- )
-
- const response = await connection.getFeeForMessage(
- message,
- 'singleGossip',
- )
-
- if (!response?.value) return
-
- setSolFee(response.value / LAMPORTS_PER_SOL)
-
- const balance = await connection.getBalance(
- new PublicKey(currentAccount?.solanaAddress),
- )
- setHasInsufficientBalance(response.value > balance)
- } catch (error) {
- Logger.error(error)
- setNetworkError((error as Error).message)
- }
- }, [])
-
- const handleInfoPress = useCallback(() => {
- if (metadata) {
- navigation.push('NftMetadataScreen', {
- metadata,
- })
- }
- }, [metadata, navigation])
-
const handleAddressBookSelected = useCallback(() => {
addressBookRef?.current?.showAddressBook({})
}, [])
@@ -144,10 +87,6 @@ const TransferCollectableScreen = () => {
[],
)
- const backgroundImageUri = useMemo(() => {
- return metadata.image
- }, [metadata])
-
const handleEditAddress = useCallback((text?: string) => {
setRecipient(text || '')
setRecipientName('')
@@ -178,25 +117,17 @@ const TransferCollectableScreen = () => {
const showError = useMemo(() => {
if (hasError) return t('generic.notValidSolanaAddress')
- if (hasInsufficientBalance) return t('generic.insufficientBalance')
if (networkError) return networkError
- }, [hasError, hasInsufficientBalance, networkError, t])
+ }, [hasError, networkError, t])
return (
-
-
+
{
enabled
keyboardVerticalOffset={100}
>
-
-
+
{metadata && (
-
+
)}
{metadata.name}
-
+
{metadata.description ||
t('collectablesScreen.collectables.noDescription')}
-
- {solFee ? (
-
+
- ) : (
-
- {t('generic.calculatingTransactionFee')}
-
- )}
+
+
+
{showError}
-
+
+
) : (
)
}
/>
-
-
+
+
-
-
+
+
+
)
}
diff --git a/src/features/collectables/TransferCompleteScreen.tsx b/src/features/collectables/TransferCompleteScreen.tsx
index 26092ebb1..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,18 +11,20 @@ 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 { 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'
import { LogBox } from 'react-native'
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 { TabBarNavigationProp } from '../../navigation/rootTypes'
+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'
import { RootState } from '../../store/rootReducer'
-import { Collectable, CompressedNFT } from '../../types/solana'
+import { CompressedNFT } from '../../types/solana'
import { ww } from '../../utils/layout'
import { CollectableStackParamList } from './collectablesTypes'
@@ -34,9 +36,11 @@ type Route = RouteProp
const TransferCollectableScreen = () => {
const route = useRoute()
- const navigation = useNavigation()
+ const colors = useColors()
+ const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
+ const navigation = useNavigation()
const COLLECTABLE_HEIGHT = ww
- const backEdges = useMemo(() => ['top'] as Edge[], [])
const solBalance = useBN(useSolOwnedAmount(useCurrentWallet()).amount)
const { t } = useTranslation()
@@ -44,182 +48,177 @@ const TransferCollectableScreen = () => {
const solanaPayment = useSelector(
(reduxState: RootState) => reduxState.solana.payment,
)
- const spacing = useSpacing()
-
- const compressedNFT = useMemo(
- () => collectable as CompressedNFT,
- [collectable],
- )
- const nft = useMemo(() => collectable as Collectable, [collectable])
+ const asset = useMemo(() => collectable as CompressedNFT, [collectable])
+ const assetImage = useMemo(() => {
+ return asset?.content?.files?.[0]?.uri
+ }, [asset])
const metadata = useMemo(() => {
- return compressedNFT?.content?.metadata || nft?.json
- }, [compressedNFT, nft])
-
- const backgroundImageUri = useMemo(() => {
- return metadata?.image
- }, [metadata.image])
+ return asset?.content?.metadata
+ }, [asset])
const onReturn = useCallback(() => {
// Reset Collectables stack to first screen
navigation.reset({
index: 0,
- routes: [{ name: 'Collectables' }],
+ routes: [{ name: 'TokensTabs' }],
})
}, [navigation])
return (
-
-
-
+
+
+
- {metadata && (
-
-
-
- )}
- {solanaPayment &&
- !solanaPayment.error &&
- !solanaPayment.loading && (
+
+ {metadata && (
+
+
+
+ )}
+ {solanaPayment &&
+ !solanaPayment.error &&
+ !solanaPayment.loading && (
+
+
+ {t('collectablesScreen.transferComplete')}
+
+
+ )}
+
+ {solanaPayment?.error && (
-
- {t('collectablesScreen.transferComplete')}
+
+ {t('collectablesScreen.transferError')}
+
+
+ {parseTransactionError(
+ solBalance,
+ solanaPayment?.error?.message,
+ )}
)}
- {solanaPayment?.error && (
-
-
- {t('collectablesScreen.transferError')}
-
-
- {parseTransactionError(
- solBalance,
- solanaPayment?.error?.message,
- )}
-
-
- )}
-
- {!solanaPayment && (
-
-
- {t('collectablesScreen.transferError')}
-
-
- )}
+
+ {t('collectablesScreen.transferError')}
+
+
+ )}
- {solanaPayment && solanaPayment.loading && (
-
-
- {t('collectablesScreen.transferingNftTitle')}
-
-
- {t('collectablesScreen.transferingNftBody')}
-
-
-
-
-
- )}
-
-
-
- }
- />
+
+ {t('collectablesScreen.transferingNftTitle')}
+
+
+ {t('collectablesScreen.transferingNftBody')}
+
+
+
+
+
+ )}
+
+
+
+ }
+ />
+
-
-
-
+
+
+
)
}
diff --git a/src/features/collectables/collectablesTypes.ts b/src/features/collectables/collectablesTypes.ts
index 566200d18..0c379b575 100644
--- a/src/features/collectables/collectablesTypes.ts
+++ b/src/features/collectables/collectablesTypes.ts
@@ -10,7 +10,7 @@ export type PaymentRouteParam = {
}
export type CollectableStackParamList = {
- CollectablesTopTab: undefined
+ HotspotList: undefined
HotspotMapScreen:
| undefined
| {
diff --git a/src/features/dappLogin/DappAccount.tsx b/src/features/dappLogin/DappAccount.tsx
index 1df7e60be..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
@@ -60,27 +60,27 @@ const DappLogin = ({ onLogin, onCancel, appName, loading }: Props) => {
flexDirection="row"
alignItems="center"
justifyContent="center"
- marginVertical="l"
+ marginVertical="6"
>
{isCrowdspot ? (
) : (
)}
-
+
-
+
{t('dappLogin.account.title', {
appName,
})}
{t('dappLogin.account.subtitle', { appName })}
@@ -96,35 +96,35 @@ const DappLogin = ({ onLogin, onCancel, appName, loading }: Props) => {
flex={1}
minHeight={66}
justifyContent="center"
- marginEnd="m"
- borderRadius="round"
+ marginEnd="4"
+ borderRadius="full"
overflow="hidden"
- backgroundColor="secondaryIcon"
+ backgroundColor="secondaryText"
onPress={onCancel}
>
-
+
{t('generic.cancel')}
{loading ? (
-
+
) : (
{t('dappLogin.login')}
diff --git a/src/features/dappLogin/DappConnect.tsx b/src/features/dappLogin/DappConnect.tsx
index e7be44d1f..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) => {
@@ -25,49 +25,49 @@ const DappConnect = ({ appName, onApprove, onDeny }: Props) => {
) : (
)}
-
+
{t('dappLogin.connect.title', { appName })}
{t('dappLogin.connect.subtitle', { appName })}
-
+
-
+
{t('generic.cancel')}
{t('dappLogin.connect.continue')}
diff --git a/src/features/dappLogin/DappLoginScreen.tsx b/src/features/dappLogin/DappLoginScreen.tsx
index 1bd9a7451..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 {
- RootNavigationProp,
- RootStackParamList,
-} from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { getKeypair } from '../../storage/secureStorage'
-import { HomeNavigationProp } from '../home/homeTypes'
+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'
@@ -57,7 +54,7 @@ const makeBurnTxn = async (opts: { payerB58: string }) => {
type Route = RouteProp
const DappLoginScreen = () => {
const route = useRoute()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const rootNav = useNavigation()
const { params } = route
const {
@@ -102,7 +99,7 @@ const DappLoginScreen = () => {
} else {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
}
}, [disconnect, navigation, rootNav])
@@ -224,17 +221,17 @@ const DappLoginScreen = () => {
return (
-
+
{body}
diff --git a/src/features/governance/AssignProxyScreen.tsx b/src/features/governance/AssignProxyScreen.tsx
index 0d2596557..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 {
@@ -110,7 +110,7 @@ export const AssignProxyScreen = () => {
return (
{
setSelectedPositions((sel) => {
@@ -229,17 +229,17 @@ export const AssignProxyScreen = () => {
-
-
+
+
{t('gov.assignProxy.description')}
-
+
{
{/* Don't show network when position already defined */}
{position ? null : (
-
-
+
+
{t('gov.assignProxy.selectNetwork')}
)}
-
+
{t('gov.assignProxy.assignPositions')}
@@ -274,7 +276,7 @@ export const AssignProxyScreen = () => {
: t('gov.assignProxy.selectAll')}
-
+
{error && (
@@ -282,15 +284,15 @@ export const AssignProxyScreen = () => {
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
+ paddingTop="3"
>
-
+
{error.toString()}
)}
-
+
{t('gov.assignProxy.expiryDate')}
{
step={1}
/>
-
+
{selectedDays} {t('gov.assignProxy.days')}
@@ -309,20 +311,20 @@ export const AssignProxyScreen = () => {
: undefined
+ isSubmitting ? : undefined
}
/>
diff --git a/src/features/governance/ClaimingRewardsModal.tsx b/src/features/governance/ClaimingRewardsModal.tsx
index ace2cf3d8..682152d8b 100644
--- a/src/features/governance/ClaimingRewardsModal.tsx
+++ b/src/features/governance/ClaimingRewardsModal.tsx
@@ -8,7 +8,7 @@ import Box from '@components/Box'
import { Edge } from 'react-native-safe-area-context'
import AccountIcon from '@components/AccountIcon'
import { useTranslation } from 'react-i18next'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { Status } from '@helium/spl-utils'
import ProgressBar from '@components/ProgressBar'
@@ -26,7 +26,7 @@ export const ClaimingRewardsModal = ({ status }: { status?: Status }) => {
return {
helpText: `Sending batch of ${actualBatchSize} transactions.\n${remainingTxs} total transaction${
- remainingTxs > 1 ? 's' : ''
+ remainingTxs > 1 ? '2' : ''
} remaining.`,
percent: (totalProgress * 100) / totalTxs,
}
@@ -45,13 +45,13 @@ export const ClaimingRewardsModal = ({ status }: { status?: Status }) => {
edges={edges}
backgroundColor="transparent"
flex={1}
- padding="m"
- marginHorizontal="s"
+ padding="4"
+ marginHorizontal="2"
marginVertical="xs"
>
{
{t('gov.claiming.title')}
-
+
{t('gov.claiming.body')}
-
+
{t('gov.claiming.multiple')}
-
+
{helpText}
diff --git a/src/features/governance/DelegateTokensModal.tsx b/src/features/governance/DelegateTokensModal.tsx
index 952885741..7054ab143 100644
--- a/src/features/governance/DelegateTokensModal.tsx
+++ b/src/features/governance/DelegateTokensModal.tsx
@@ -77,19 +77,23 @@ export const DelegateTokensModal = ({
onClose={handleOnClose}
backgroundColor="transparent"
flex={1}
- padding="m"
- marginHorizontal="s"
+ padding="4"
+ marginHorizontal="2"
>
{!loading && (
<>
-
+
{t('gov.transactions.delegatePosition')}
{t('gov.positions.selectSubDao')}
@@ -98,7 +102,11 @@ export const DelegateTokensModal = ({
{loading && (
-
+
{t('gov.positions.fetchingSubDaos')}
@@ -114,18 +122,18 @@ export const DelegateTokensModal = ({
return (
0 ? 'm' : 'none'}
+ borderRadius="2xl"
+ marginTop={idx > 0 ? '4' : 'none'}
backgroundColor={
- isSelected ? 'secondaryBackground' : 'secondary'
+ isSelected ? 'secondaryBackground' : 'bg.tertiary'
}
onPress={() => setSelectedSubDaoPk(subDao.pubkey)}
>
-
+
{subDao.dntMetadata.name}
@@ -150,29 +158,29 @@ export const DelegateTokensModal = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
+ paddingTop="3"
>
-
+
{showError}
)}
-
+
: undefined
+ isSubmitting ? : undefined
}
/>
diff --git a/src/features/governance/GovernanceNavigator.tsx b/src/features/governance/GovernanceNavigator.tsx
index d096b542e..33bf4eeff 100644
--- a/src/features/governance/GovernanceNavigator.tsx
+++ b/src/features/governance/GovernanceNavigator.tsx
@@ -3,8 +3,9 @@ import {
StackNavigationOptions,
createStackNavigator,
} from '@react-navigation/stack'
-import { useAppStorage } from '@storage/AppStorageProvider'
-import React, { memo } from 'react'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
+import React, { memo, useMemo } from 'react'
+import { useColors } from '@config/theme/themeHooks'
import AssignProxyScreen from './AssignProxyScreen'
import GovernanceTutorialScreen from './GovernanceTutorialScreen'
import PositionsScreen from './PositionsScreen'
@@ -15,14 +16,19 @@ import VoterScreen from './VoterScreen'
import VotersScreen from './VotersScreen'
const GovernanceStack = createStackNavigator()
-const screenOptions: StackNavigationOptions = {
- headerShown: false,
- animationEnabled: false,
-}
-
const GovernanceStackScreen = () => {
+ const colors = useColors()
const { voteTutorialShown } = useAppStorage()
+ const screenOptions: StackNavigationOptions = useMemo(
+ () => ({
+ headerShown: false,
+ animationEnabled: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ }),
+ [colors],
+ )
+
return (
<>
diff --git a/src/features/governance/GovernanceTutorialScreen.tsx b/src/features/governance/GovernanceTutorialScreen.tsx
index 7384589fe..076d5526c 100644
--- a/src/features/governance/GovernanceTutorialScreen.tsx
+++ b/src/features/governance/GovernanceTutorialScreen.tsx
@@ -1,19 +1,18 @@
import { useNavigation } from '@react-navigation/native'
import React, { memo, useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { Edge } from 'react-native-safe-area-context'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { Carousel, Pagination } from 'react-native-snap-carousel'
import Box from '@components/Box'
-import CloseButton from '@components/CloseButton'
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 { NativeViewGestureHandler } from 'react-native-gesture-handler'
import { GovernanceNavigationProp } from './governanceTypes'
type CarouselItem = {
@@ -28,7 +27,7 @@ const slides: Array = [
titleKey: 'gov.tutorial.slides.0.title',
bodyKey: 'gov.tutorial.slides.0.body',
image: require('@assets/images/voteSlide0.png'),
- imageVerticalOffset: 'n_xxl',
+ imageVerticalOffset: '-12',
},
{
titleKey: 'gov.tutorial.slides.1.title',
@@ -39,19 +38,19 @@ const slides: Array = [
titleKey: 'gov.tutorial.slides.2.title',
bodyKey: 'gov.tutorial.slides.2.body',
image: require('@assets/images/voteSlide2.png'),
- imageVerticalOffset: 'xxl',
+ imageVerticalOffset: '12',
},
{
titleKey: 'gov.tutorial.slides.3.title',
bodyKey: 'gov.tutorial.slides.3.body',
image: require('@assets/images/voteSlide3.png'),
- imageVerticalOffset: 'xxl',
+ imageVerticalOffset: '12',
},
{
titleKey: 'gov.tutorial.slides.4.title',
bodyKey: 'gov.tutorial.slides.4.body',
image: require('@assets/images/voteSlide4.png'),
- imageVerticalOffset: 'xxl',
+ imageVerticalOffset: '12',
},
]
@@ -64,7 +63,7 @@ export const GovernanceTutorialScreen = () => {
const colors = useColors()
const navigation = useNavigation()
const { setVoteTutorialCompleted } = useAppStorage()
- const edges = useMemo(() => ['top'] as Edge[], [])
+ const { bottom } = useSafeAreaInsets()
const handleVotePressed = useCallback(() => {
setVoteTutorialCompleted()
@@ -82,26 +81,27 @@ export const GovernanceTutorialScreen = () => {
// eslint-disable-next-line react/no-unused-prop-types
({ item }: { item: CarouselItem }) => {
return (
-
+
{t(item.titleKey)}
@@ -115,30 +115,28 @@ export const GovernanceTutorialScreen = () => {
width: 6,
height: 6,
borderRadius: 3,
- marginHorizontal: spacing.s,
- backgroundColor: colors.white,
+ marginHorizontal: spacing['0.5'],
+ backgroundColor: colors.primaryText,
}),
- [colors.white, spacing.s],
+ [colors, spacing],
)
return (
-
-
-
-
+
+
+
+
+
+
{
inactiveDotScale={1}
/>
-
+
-
+
)
}
diff --git a/src/features/governance/GovernanceWrapper.tsx b/src/features/governance/GovernanceWrapper.tsx
index b3eecfa9d..e470b50de 100644
--- a/src/features/governance/GovernanceWrapper.tsx
+++ b/src/features/governance/GovernanceWrapper.tsx
@@ -1,20 +1,17 @@
/* eslint-disable @typescript-eslint/no-shadow */
-import Flag from '@assets/images/flag.svg'
-import LightningBolt from '@assets/images/lightningBolt.svg'
-import UserStar from '@assets/images/userStar.svg'
+import Flag from '@assets/svgs/flag.svg'
+import LightningBolt from '@assets/svgs/lightningBolt.svg'
+import UserStar from '@assets/svgs/userStar.svg'
import { ReAnimatedBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import CircleLoader from '@components/CircleLoader'
-import SafeAreaBox from '@components/SafeAreaBox'
import { Select } from '@components/Select'
-import Text from '@components/Text'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { useGovernance } from '@storage/GovernanceProvider'
-import globalStyles from '@theme/globalStyles'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import React, { useEffect, useMemo, useRef } from 'react'
-import { useTranslation } from 'react-i18next'
import { Animated } from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
+import { FadeIn } from 'react-native-reanimated'
+import { useColors } from '@config/theme/themeHooks'
import {
GovernanceNavigationProp,
GovernanceStackParamList,
@@ -22,12 +19,6 @@ import {
import { useSetTab } from './useSetTab'
import { NetworkTabs } from './NetworkTabs'
-const icons: { [key: string]: React.ReactElement } = {
- proposals: ,
- voters: ,
- positions: ,
-}
-
type Route = RouteProp
export const GovernanceWrapper: React.FC<
React.PropsWithChildren<{
@@ -35,13 +26,23 @@ export const GovernanceWrapper: React.FC<
header?: React.ReactElement
}>
> = ({ selectedTab, children, header }) => {
- const { t } = useTranslation()
const route = useRoute()
const navigation = useNavigation()
- const safeEdges = useMemo(() => ['top'] as Edge[], [])
const { loading, hasUnseenProposals } = useGovernance()
const anim = useRef(new Animated.Value(1))
const setSelectedTab = useSetTab()
+ const colors = useColors()
+
+ const icons: { [key: string]: React.ReactElement } = useMemo(
+ () => ({
+ proposals: ,
+ voters: (
+
+ ),
+ positions: ,
+ }),
+ [colors],
+ )
useEffect(() => {
// if we have a mint and proposal, navigate to the proposal screen
@@ -86,25 +87,23 @@ export const GovernanceWrapper: React.FC<
}, [loading, hasUnseenProposals])
return (
-
-
+
+
-
- {t('gov.title')}
-
-
+
{loading ? (
-
-
+
+
) : (
-
+
{header}
)}
-
+
)
}
diff --git a/src/features/governance/LockTokensModal.tsx b/src/features/governance/LockTokensModal.tsx
index b3b0f39dc..f424f3b2f 100644
--- a/src/features/governance/LockTokensModal.tsx
+++ b/src/features/governance/LockTokensModal.tsx
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import Close from '@assets/images/close.svg'
-import InfoIcon from '@assets/images/info.svg'
-import { ReAnimatedBlurBox } from '@components/AnimatedBox'
+import Close from '@assets/svgs/close.svg'
+import InfoIcon from '@assets/svgs/info.svg'
+import { ReAnimatedBox } from '@components/AnimatedBox'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
@@ -17,7 +17,7 @@ import { useMint } from '@helium/helium-react-hooks'
import { HNT_MINT, toBN, toNumber } from '@helium/spl-utils'
import { SubDaoWithMeta, useSubDaos } from '@helium/voter-stake-registry-hooks'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { getFormattedStringFromDays, yearsToDays } from '@utils/dateTools'
import { getMintMinAmountAsDecimal, precision } from '@utils/formatting'
import { TXN_FEE_IN_LAMPORTS } from '@utils/solanaUtils'
@@ -30,8 +30,9 @@ import {
TouchableWithoutFeedback,
} from 'react-native'
import { Edge } from 'react-native-safe-area-context'
-import HntIcon from '@assets/images/helium.svg'
-import { ScrollView } from 'react-native-gesture-handler'
+import HntIcon from '@assets/svgs/helium.svg'
+import ScrollBox from '@components/ScrollBox'
+import { useColors } from '@config/theme/themeHooks'
const SOL_TXN_FEE = new BN(TXN_FEE_IN_LAMPORTS)
export const defaultLockupPeriods = [
@@ -103,6 +104,7 @@ export const LockTokensModal = ({
onSubmit: (values: LockTokensModalFormValues) => Promise
}) => {
const { t } = useTranslation()
+ const colors = useColors()
const { currentAccount } = useAccountStorage()
const backEdges = useMemo(() => ['top'] as Edge[], [])
const { info: mintAcc } = useMint(mint)
@@ -230,12 +232,13 @@ export const LockTokensModal = ({
return (
-
{step === 1 && (
Keyboard.dismiss()}>
@@ -254,247 +257,105 @@ export const LockTokensModal = ({
enabled
keyboardVerticalOffset={100}
>
-
-
- {!showLockupKindInfo && (
-
-
+
+ {!showLockupKindInfo && (
+
+
+ {
{
- {
- lock: t('gov.transactions.lockTokens'),
- extend: t('gov.transactions.extendPosition'),
- split: t('gov.transactions.splitPosition'),
- }[mode]
- }
-
-
+
+ {t('gov.votingPower.increase')}
+
+ {hasMinLockup ? (
+
- {t('gov.votingPower.increase')}
-
- {hasMinLockup ? (
-
-
- {t('gov.positions.longerLockup', {
- existing:
- getFormattedStringFromDays(
- minLockupTimeInDays,
- ),
- })}
+
+ {t('gov.positions.longerLockup', {
+ existing:
+ getFormattedStringFromDays(minLockupTimeInDays),
+ })}
+
+ {mode === 'split' ? (
+
+ {t('gov.positions.splitWarning')}
- {mode === 'split' ? (
-
- {t('gov.positions.splitWarning')}
-
- ) : null}
-
- ) : null}
-
- {['lock', 'split'].includes(mode) && (
- <>
-
-
-
- {t('gov.positions.lockupType')}
-
- setShowLockupKindInfo(true)}
- >
-
-
-
-
- {lockupKindOptions.map((option, idx) => {
- const isActive =
- option.value === lockupKind.value
-
- return (
- 0 ? 'ms' : 'none'}
- backgroundColor={
- isActive
- ? 'surfaceSecondary'
- : 'black500'
- }
- onPress={() => {
- setLockupKind(option)
- }}
- >
-
- {option.display}
-
-
- )
- })}
-
-
-
-
- {t('gov.positions.amountToLock')}
-
-
- {amount || 'Amount (tokens)'}
-
-
- >
- )}
- {!showCustomDuration && (
-
+ ) : null}
+
+ ) : null}
+
+ {['lock', 'split'].includes(mode) && (
+ <>
+
- {t('gov.positions.duration')}
+ {t('gov.positions.lockupType')}
- setShowCustomDuration(
- (oldValue) => !oldValue,
- )
- }
+ onPress={() => setShowLockupKindInfo(true)}
>
-
- {t('gov.positions.customDuration')}
-
+
- {hasMinLockup ? (
-
- {
- setLockupPeriod(lockupPeriodOptions[0])
- setShowCustomDuration(false)
- }}
- >
-
- {getFormattedStringFromDays(
- minLockupTimeInDays,
- )}
-
-
-
- ) : null}
-
- {(hasMinLockup
- ? [...lockupPeriodOptions.splice(1)]
- : lockupPeriodOptions
- ).map((option, idx) => {
+
+ {lockupKindOptions.map((option, idx) => {
const isActive =
- !showCustomDuration &&
- option.value === lockupPeriod.value
+ option.value === lockupKind.value
return (
0 ? 's' : 'none'}
+ borderRadius="2xl"
+ marginLeft={idx > 0 ? '3' : 'none'}
backgroundColor={
- isActive
- ? 'surfaceSecondary'
- : 'black500'
+ isActive ? 'primaryText' : 'transparent'
}
onPress={() => {
- setLockupPeriod(option)
- setShowCustomDuration(false)
+ setLockupKind(option)
}}
>
{option.display}
@@ -504,108 +365,240 @@ export const LockTokensModal = ({
})}
- )}
- {showCustomDuration && (
- }
- TrailingIconOptions={{
- onPress: () => {
- setShowCustomDuration(false)
- setLockupPeriodInDays(lockupPeriod.value)
- },
- }}
- textInputProps={{
- placeholder: t(
- 'gov.positions.customDurationPlaceholder',
- ),
- value: lockupPeriodInDays.toString(),
- keyboardType: 'numeric',
- onChangeText: (text) =>
- setLockupPeriodInDays(Number(text || 0)),
- onBlur: () => {
- const val = lockupPeriodInDays
-
- setLockupPeriodInDays(
- // eslint-disable-next-line no-nested-ternary
- val > minLockupTimeInDays
- ? val > maxLockupTimeInDays
- ? maxLockupTimeInDays
- : val
- : minLockupTimeInDays,
- )
- },
- }}
- />
- )}
-
+
+
+ {t('gov.positions.amountToLock')}
+
+
+ {amount || 'Amount (tokens)'}
+
+
+ >
+ )}
+ {!showCustomDuration && (
+
-
- {t('gov.positions.initialVotePowerMult')}:
-
-
- {lockupMultiplier}x
+
+ {t('gov.positions.duration')}
+
+ setShowCustomDuration((oldValue) => !oldValue)
+ }
+ >
+
+ {t('gov.positions.customDuration')}
+
+
+ {hasMinLockup ? (
+
+ {
+ setLockupPeriod(lockupPeriodOptions[0])
+ setShowCustomDuration(false)
+ }}
+ >
+
+ {getFormattedStringFromDays(
+ minLockupTimeInDays,
+ )}
+
+
+
+ ) : null}
+
+ {(hasMinLockup
+ ? [...lockupPeriodOptions.splice(1)]
+ : lockupPeriodOptions
+ ).map((option, idx) => {
+ const isActive =
+ !showCustomDuration &&
+ option.value === lockupPeriod.value
+
+ return (
+ 0 ? '2' : 'none'}
+ backgroundColor={
+ isActive ? 'primaryText' : 'transparent'
+ }
+ onPress={() => {
+ setLockupPeriod(option)
+ setShowCustomDuration(false)
+ }}
+ >
+
+ {option.display}
+
+
+ )
+ })}
+
+
+ )}
+ {showCustomDuration && (
+ (
+
+ )}
+ TrailingIconOptions={{
+ onPress: () => {
+ setShowCustomDuration(false)
+ setLockupPeriodInDays(lockupPeriod.value)
+ },
+ }}
+ textInputProps={{
+ placeholder: t(
+ 'gov.positions.customDurationPlaceholder',
+ ),
+ value: lockupPeriodInDays.toString(),
+ keyboardType: 'numeric',
+ onChangeText: (text) =>
+ setLockupPeriodInDays(Number(text || 0)),
+ onBlur: () => {
+ const val = lockupPeriodInDays
+
+ setLockupPeriodInDays(
+ // eslint-disable-next-line no-nested-ternary
+ val > minLockupTimeInDays
+ ? val > maxLockupTimeInDays
+ ? maxLockupTimeInDays
+ : val
+ : minLockupTimeInDays,
+ )
+ },
+ }}
+ />
+ )}
+
+
+
+ {t('gov.positions.initialVotePowerMult')}:
+
+
+ {lockupMultiplier}x
+
+
+
-
-
+ height={6}
+ width={`${lockupMultiplier}%`}
+ backgroundColor="blue.light-500"
+ />
- )}
- {showLockupKindInfo && (
-
- {lockupKindOptions.map((type) => (
-
+
+ )}
+ {showLockupKindInfo && (
+
+ {lockupKindOptions.map((type) => (
+
+
+ {type.display}
+
+ {lockupInfosByType[type.value].map((info, idx) => (
- {type.display}
+ {info}
- {lockupInfosByType[type.value].map((info, idx) => (
-
- {info}
-
- ))}
-
- ))}
-
- )}
-
-
+ ))}
+
+ ))}
+
+ )}
+
)}
@@ -615,25 +608,25 @@ export const LockTokensModal = ({
<>
{t('gov.transactions.delegatePosition')}
{t('gov.positions.selectSubDao')}
-
+
{t('gov.positions.delegateBlurb')}
@@ -643,9 +636,9 @@ export const LockTokensModal = ({
{t('gov.positions.fetchingSubDaos')}
@@ -654,24 +647,28 @@ export const LockTokensModal = ({
{subDaos && (
setSelectedSubDaoPk(null)}
>
-
+
-
+
None
@@ -688,22 +685,22 @@ export const LockTokensModal = ({
return (
setSelectedSubDaoPk(subDao.pubkey)}
>
{subDao.dntMetadata.name}
@@ -729,25 +728,25 @@ export const LockTokensModal = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
+ paddingTop="3"
>
-
+
{showError}
)}
{step === 1 && (
-
+
{!showLockupKindInfo ? (
: undefined
+ isSubmitting ? (
+
+ ) : undefined
}
/>
) : (
{
setShowLockupKindInfo(false)
}}
@@ -802,28 +803,41 @@ export const LockTokensModal = ({
)}
{step === 2 && (
-
+
: undefined
+ isSubmitting ? (
+
+ ) : undefined
}
/>
)}
-
+
+
)
}
diff --git a/src/features/governance/NetworkTabs.tsx b/src/features/governance/NetworkTabs.tsx
index 78f19bc65..99e64d0e9 100644
--- a/src/features/governance/NetworkTabs.tsx
+++ b/src/features/governance/NetworkTabs.tsx
@@ -1,83 +1,56 @@
import Box from '@components/Box'
-import TokenPill from '@components/TokenPill'
import { useNavigation } from '@react-navigation/native'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useGovernance } from '@storage/GovernanceProvider'
-import { GovMints } from '@utils/constants'
-import React, { useRef } from 'react'
-import { Animated } from 'react-native'
+import React, { useCallback, useMemo } from 'react'
+import SegmentedControl from '@components/SegmentedControl'
+import { Mints } from '@utils/constants'
+import IOT from '@assets/svgs/iotSymbol.svg'
+import MOBILE from '@assets/svgs/mobileIcon.svg'
+import HNT from '@assets/svgs/tokenHNT.svg'
import { GovernanceNavigationProp } from './governanceTypes'
export const NetworkTabs: React.FC = () => {
const navigation = useNavigation()
- const { currentAccount } = useAccountStorage()
- const { mint, proposalCountByMint } = useGovernance()
- const anim = useRef(new Animated.Value(1))
+ const options = useMemo(
+ () => [
+ {
+ label: 'HNT',
+ value: Mints.HNT,
+ Icon: HNT,
+ iconProps: { width: 20, height: 20 },
+ },
+ {
+ label: 'MOBILE',
+ value: Mints.MOBILE,
+ Icon: MOBILE,
+ iconProps: { width: 20, height: 20 },
+ },
+ {
+ label: 'IOT',
+ value: Mints.IOT,
+ Icon: IOT,
+ iconProps: { width: 20, height: 20 },
+ },
+ ],
+ [],
+ )
- return (
-
- {GovMints.map((m) => {
- const pk = new PublicKey(m)
- const hasUnseenProposals =
- (proposalCountByMint?.[m] || 0) >
- (currentAccount?.proposalCountByMint?.[m] || 0)
+ const onItemSelected = useCallback(
+ (index: number) => {
+ const pk = new PublicKey(options[index].value)
+ navigation.setParams({ mint: pk.toBase58() })
+ },
+ [navigation, options],
+ )
- return (
-
- navigation.setParams({ mint: pk.toBase58() })}
- inactiveColor="secondaryBackground"
- activeColor="secondary"
- />
- {!mint.equals(pk) && hasUnseenProposals && (
-
-
-
-
-
-
-
-
-
-
- )}
-
- )
- })}
+ return (
+
+
)
}
diff --git a/src/features/governance/PositionCard.tsx b/src/features/governance/PositionCard.tsx
index bc380f52d..c84c4fbe9 100644
--- a/src/features/governance/PositionCard.tsx
+++ b/src/features/governance/PositionCard.tsx
@@ -40,9 +40,9 @@ import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { useNavigation } from '@react-navigation/native'
import { BoxProps } from '@shopify/restyle'
import { Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
-import { Theme } from '@theme/theme'
-import { useCreateOpacity } from '@theme/themeHooks'
+import { useGovernance } from '@config/storage/GovernanceProvider'
+import { Theme } from '@config/theme/theme'
+import { useCreateOpacity } from '@config/theme/themeHooks'
import { MAX_TRANSACTIONS_PER_SIGNATURE_BATCH } from '@utils/constants'
import {
daysToSecs,
@@ -58,10 +58,10 @@ import React, { useCallback, useMemo, useRef, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { FadeIn, FadeOut } from 'react-native-reanimated'
-import { MessagePreview } from '../../solana/MessagePreview'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useWalletSign } from '../../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../../solana/walletSignBottomSheetTypes'
+import { MessagePreview } from '@features/solana/MessagePreview'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import { DelegateTokensModal } from './DelegateTokensModal'
import LockTokensModal, { LockTokensModalFormValues } from './LockTokensModal'
import { TransferTokensModal } from './TransferTokensModal'
@@ -435,6 +435,7 @@ export const PositionCard = ({
lockupPeriodsInDays: values.lockupPeriodInDays,
onInstructions: async (ixs, sigs) => {
await decideAndExecute({
+ sequentially: true,
header: t('gov.transactions.splitPosition'),
message: t('gov.positions.splitMessage', {
amount: values.amount,
@@ -759,14 +760,14 @@ export const PositionCard = ({
<>
{isLoading && (
-
+
{isSpliting && t('gov.positions.splitting')}
{isExtending && t('gov.positions.extending')}
{isTransfering && t('gov.positions.transfering')}
@@ -777,7 +778,7 @@ export const PositionCard = ({
{isUndelegating && t('gov.positions.undelegating')}
{isRelinquishing && t('gov.positions.relinquishing')}
-
+
@@ -786,39 +787,43 @@ export const PositionCard = ({
{!isLoading && (
<>
setActionsOpen(true)}>
-
+
{json?.image ? (
) : undefined}
{`${lockedTokens} ${symbol}`}
{hasGenesisMultiplier && (
-
+
{t('gov.positions.landrush').toUpperCase()}
@@ -827,25 +832,29 @@ export const PositionCard = ({
-
+
{t('gov.positions.lockupType')}
-
+
{lockupKindDisplay}
{t('gov.positions.voteMult')}
-
+
{(
(position.votingPower.isZero()
? 0
@@ -863,12 +872,12 @@ export const PositionCard = ({
-
+
{isConstant
? t('gov.positions.minDur')
: t('gov.positions.timeLeft')}
-
+
{isConstant
? getMinDurationFmt(
position.lockup.startTs,
@@ -880,14 +889,14 @@ export const PositionCard = ({
{hasGenesisMultiplier && (
{t('gov.positions.landrush')}
@@ -897,22 +906,22 @@ export const PositionCard = ({
)}
-
+
{delegatedSubDaoMetadata ? (
-
+
{t('gov.positions.delegatedTo')}
{delegatedSubDaoMetadata.name}
@@ -937,10 +946,10 @@ export const PositionCard = ({
delegatedSubDaoMetadata ? 'flex-end' : 'flex-start'
}
>
-
+
{t('gov.positions.proxiedTo')}
-
+
-
-
+
+
{showError}
diff --git a/src/features/governance/PositionPreview.tsx b/src/features/governance/PositionPreview.tsx
index ffd4bc4a9..46843de6c 100644
--- a/src/features/governance/PositionPreview.tsx
+++ b/src/features/governance/PositionPreview.tsx
@@ -1,13 +1,13 @@
-import Hnt from '@assets/images/hnt.svg'
-import Iot from '@assets/images/iot.svg'
-import Mobile from '@assets/images/mobile.svg'
+import Hnt from '@assets/svgs/hnt.svg'
+import Iot from '@assets/svgs/iot.svg'
+import Mobile from '@assets/svgs/mobile.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableContainer, {
ButtonPressAnimationProps,
} from '@components/TouchableContainer'
import { PositionWithMeta } from '@helium/voter-stake-registry-hooks'
-import { useGovernance } from '@storage/GovernanceProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
import { getMinDurationFmt } from '@utils/dateTools'
import { humanReadable } from '@utils/formatting'
import BN from 'bn.js'
@@ -62,23 +62,23 @@ export const PositionPreview: React.FC<
return (
- {Icon}
+ {Icon}
-
+
{amount} {network.toUpperCase()}
-
+
for
-
+
{position.lockup?.endTs
? getMinDurationFmt(
new BN(Date.now() / 1000),
@@ -86,17 +86,22 @@ export const PositionPreview: React.FC<
)
: null}
-
+
{position.lockup?.kind?.cliff ? 'decaying' : 'decaying delayed'}
{subDao && (
-
+
and delegated to
{DelegatedIcon}
- {subDao.dntMetadata.symbol}
+ {subDao.dntMetadata.symbol}
)}
diff --git a/src/features/governance/PositionsList.tsx b/src/features/governance/PositionsList.tsx
index 2ae353cd2..28699f9c6 100644
--- a/src/features/governance/PositionsList.tsx
+++ b/src/features/governance/PositionsList.tsx
@@ -1,4 +1,4 @@
-import LightningBolt from '@assets/images/transactions.svg'
+import LightningBolt from '@assets/svgs/transactions.svg'
import Box from '@components/Box'
import { CardSkeleton } from '@components/CardSkeleton'
import Text from '@components/Text'
@@ -7,13 +7,14 @@ import {
useSubDaos,
} from '@helium/voter-stake-registry-hooks'
import { BoxProps } from '@shopify/restyle'
-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 { times } from 'lodash'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { RefreshControl, SectionList } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
import { PositionCard } from './PositionCard'
interface IPositionsListProps extends BoxProps {
@@ -74,7 +75,7 @@ export const PositionsList = ({ header, ...boxProps }: IPositionsListProps) => {
// eslint-disable-next-line react/no-array-index-key
key={`${p.pubkey.toBase58()}-${p.amountDepositedNative.toString()}-${idx}`}
position={p}
- marginTop={idx > 0 ? 'm' : 'none'}
+ marginTop={idx > 0 ? '4' : 'none'}
subDaos={subDaos}
/>
)
@@ -102,15 +103,15 @@ export const PositionsList = ({ header, ...boxProps }: IPositionsListProps) => {
return (
-
+
{t('gov.positions.noneFound')}
@@ -129,14 +130,14 @@ export const PositionsList = ({ header, ...boxProps }: IPositionsListProps) => {
{icon !== undefined && icon}
-
+
{title}
@@ -145,50 +146,7 @@ export const PositionsList = ({ header, ...boxProps }: IPositionsListProps) => {
)
return (
-
- {header}
-
-
- Positions
-
-
-
-
-
-
- Increase your voting power by locking tokens
-
-
-
- >
- }
- keyExtractor={keyExtractor}
- sections={loading ? [] : SectionData}
- renderItem={renderItem}
- ListEmptyComponent={renderEmptyComponent}
+ {
tintColor={colors.primaryText}
/>
}
- />
+ >
+
+ {header}
+
+
+ Positions
+
+
+
+
+
+
+ Increase your voting power by locking tokens
+
+
+
+ >
+ }
+ keyExtractor={keyExtractor}
+ sections={loading ? [] : SectionData}
+ renderItem={renderItem}
+ ListEmptyComponent={renderEmptyComponent}
+ />
+
)
}
diff --git a/src/features/governance/PositionsScreen.tsx b/src/features/governance/PositionsScreen.tsx
index 8c4edbde5..313072c1b 100644
--- a/src/features/governance/PositionsScreen.tsx
+++ b/src/features/governance/PositionsScreen.tsx
@@ -23,17 +23,20 @@ import {
import { useCurrentWallet } from '@hooks/useCurrentWallet'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { Keypair, 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 { daysToSecs, getFormattedStringFromDays } from '@utils/dateTools'
import { getBasePriorityFee } from '@utils/walletApiV2'
import BN from 'bn.js'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { MessagePreview } from '../../solana/MessagePreview'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useWalletSign } from '../../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../../solana/walletSignBottomSheetTypes'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { useSpacing } from '@config/theme/themeHooks'
+import ScrollBox from '@components/ScrollBox'
+import { MessagePreview } from '@features/solana/MessagePreview'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import { ClaimingRewardsModal } from './ClaimingRewardsModal'
import GovernanceWrapper from './GovernanceWrapper'
import LockTokensModal, { LockTokensModalFormValues } from './LockTokensModal'
@@ -42,6 +45,8 @@ import { VotingPowerCard } from './VotingPowerCard'
export const PositionsScreen = () => {
const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+ const spacing = useSpacing()
const wallet = useCurrentWallet()
const { walletSignBottomSheetRef } = useWalletSign()
const [isLockModalOpen, setIsLockModalOpen] = useState(false)
@@ -234,82 +239,83 @@ export const PositionsScreen = () => {
}
return (
-
-
-
- } />
-
- {showError && (
+
+
+
+
+ } />
+
+ {showError && (
+
+
+ {showError}
+
+
+ )}
-
- {showError}
-
+ setIsLockModalOpen(true)}
+ disabled={claimingAllRewards || loading}
+ />
+ {HNT_MINT.equals(mint) && (
+ <>
+
+ >
+ )}
- )}
-
- setIsLockModalOpen(true)}
- disabled={claimingAllRewards || loading}
- />
- {HNT_MINT.equals(mint) && (
- <>
-
-
- >
+ {claimingAllRewards && (
+
+ )}
+ {isLockModalOpen && (
+ setIsLockModalOpen(false)}
+ onSubmit={handleLockTokens}
+ />
)}
- {claimingAllRewards && }
- {isLockModalOpen && (
- setIsLockModalOpen(false)}
- onSubmit={handleLockTokens}
- />
- )}
-
-
+
+
)
}
diff --git a/src/features/governance/ProposalCard.tsx b/src/features/governance/ProposalCard.tsx
index 20f1d9971..e8e3ce40c 100644
--- a/src/features/governance/ProposalCard.tsx
+++ b/src/features/governance/ProposalCard.tsx
@@ -9,8 +9,8 @@ import {
} from '@helium/modular-governance-hooks'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { useGovernance } from '@storage/GovernanceProvider'
-import { Theme } from '@theme/theme'
+import { useGovernance } from '@config/storage/GovernanceProvider'
+import { Theme } from '@config/theme/theme'
import { humanReadable } from '@utils/formatting'
import axios from 'axios'
import BN from 'bn.js'
@@ -20,7 +20,7 @@ import { useAsync } from 'react-async-hook'
import { FadeIn, FadeOut } from 'react-native-reanimated'
import { useTranslation } from 'react-i18next'
import { getTimeFromNowFmt } from '@utils/dateTools'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
import { getDerivedProposalState } from '@utils/governanceUtils'
import { ProposalFilter, ProposalV0 } from './governanceTypes'
import { ProposalTags } from './ProposalTags'
@@ -36,9 +36,9 @@ const markdownParser = MarkdownIt()
export const ProposalCardSkeleton = (boxProps: BoxProps) => (
{!hasSeen && derivedState === 'active' && !completed && (
-
+
-
+
UNSEEN
)}
{hasSeen && derivedState === 'active' && !completed && (
-
+
-
+
ACTIVE
@@ -182,15 +192,15 @@ export const ProposalCard = ({
justifyContent="space-between"
alignItems="center"
>
-
+
{proposal?.name}
{derivedState === 'active' && (
{!descError && desc ? desc : t('gov.proposals.noDescription')}
@@ -204,65 +214,73 @@ export const ProposalCard = ({
borderTopWidth={2}
borderBottomColor="primaryBackground"
borderBottomWidth={2}
- paddingHorizontal="m"
- paddingVertical="s"
+ paddingHorizontal="4"
+ paddingVertical="2"
>
-
+
You Voted - Yes
)} */}
{}
{derivedState === 'active' && !completed && (
-
+
{t('gov.proposals.estTime')}
)}
{derivedState === 'active' && completed && (
-
+
{t('gov.proposals.votingClosed')}
)}
{derivedState === 'passed' && (
-
+
{t('gov.proposals.success')}
)}
{derivedState === 'completed' && (
-
+
{t('gov.proposals.completed')}
)}
{derivedState === 'failed' && (
-
+
{t('gov.proposals.failed')}
)}
{derivedState === 'cancelled' && (
-
+
{t('gov.proposals.cancelled')}
)}
{derivedState !== 'cancelled' && (
-
+
{getTimeFromNowFmt(endTs || new BN(0))}
)}
{derivedState !== 'cancelled' && (
-
+
{t('gov.proposals.votes')}
-
+
{humanReadable(votingResults?.totalVotes, decimals) || 'None'}
diff --git a/src/features/governance/ProposalScreen.tsx b/src/features/governance/ProposalScreen.tsx
index 8c6e9a85c..7dbde690d 100644
--- a/src/features/governance/ProposalScreen.tsx
+++ b/src/features/governance/ProposalScreen.tsx
@@ -1,4 +1,4 @@
-import BrowseVoters from '@assets/images/browseVoters.svg'
+import BrowseVoters from '@assets/svgs/browseVoters.svg'
import { ReAnimatedBox } from '@components/AnimatedBox'
import BackScreen from '@components/BackScreen'
import Box from '@components/Box'
@@ -27,9 +27,9 @@ import {
} from '@helium/voter-stake-registry-hooks'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useGovernance } from '@storage/GovernanceProvider'
-import globalStyles from '@theme/globalStyles'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
+import globalStyles from '@config/theme/globalStyles'
import { MAX_TRANSACTIONS_PER_SIGNATURE_BATCH } from '@utils/constants'
import { getTimeFromNowFmt } from '@utils/dateTools'
import { humanReadable } from '@utils/formatting'
@@ -40,12 +40,13 @@ import BN from 'bn.js'
import React, { useCallback, useMemo, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
-import { ScrollView } from 'react-native'
import { Edge } from 'react-native-safe-area-context'
-import { MessagePreview } from '../../solana/MessagePreview'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useWalletSign } from '../../solana/WalletSignProvider'
-import { WalletStandardMessageTypes } from '../../solana/walletSignBottomSheetTypes'
+import ScrollBox from '@components/ScrollBox'
+import { useColors } from '@config/theme/themeHooks'
+import { MessagePreview } from '@features/solana/MessagePreview'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useWalletSign } from '@features/solana/WalletSignProvider'
+import { WalletStandardMessageTypes } from '@features/solana/walletSignBottomSheetTypes'
import { VoteOption } from './VoteOption'
import {
GovernanceNavigationProp,
@@ -58,6 +59,7 @@ import {
type Route = RouteProp
export const ProposalScreen = () => {
const { t } = useTranslation()
+ const colors = useColors()
const route = useRoute()
const navigation = useNavigation()
const { upsertAccount, currentAccount } = useAccountStorage()
@@ -282,8 +284,8 @@ export const ProposalScreen = () => {
return (
@@ -291,16 +293,16 @@ export const ProposalScreen = () => {
edges={safeEdges}
backgroundColor="transparent"
flex={1}
- marginTop="l"
+ marginTop="6"
>
-
-
+
+
{proposal?.tags
@@ -308,61 +310,61 @@ export const ProposalScreen = () => {
.map((tag, idx) => (
0 ? 's' : 'none'}
- padding="s"
+ marginLeft={idx > 0 ? '2' : 'none'}
+ padding="2"
backgroundColor={
tag.toLowerCase().includes('temp check')
- ? 'orange500'
- : 'black600'
+ ? 'orange.500'
+ : 'secondaryBackground'
}
- borderRadius="m"
+ borderRadius="2xl"
>
-
+
{tag.toUpperCase()}
))}
-
-
+
+
{proposal?.name}
-
+
{derivedState === 'active' && !completed && (
-
+
{t('gov.proposals.estTime')}
)}
{derivedState === 'active' && completed && (
-
+
{t('gov.proposals.votingClosed')}
)}
{derivedState === 'passed' && (
-
+
{t('gov.proposals.success')}
)}
{derivedState === 'completed' && (
-
+
{t('gov.proposals.completed')}
)}
{derivedState === 'failed' && (
-
+
{t('gov.proposals.failed')}
)}
{derivedState === 'cancelled' && (
-
+
{t('gov.proposals.cancelled')}
)}
{derivedState !== 'cancelled' && (
-
+
{getTimeFromNowFmt(endTs || new BN(0))}
)}
@@ -370,14 +372,14 @@ export const ProposalScreen = () => {
{derivedState !== 'cancelled' && (
{t('gov.proposals.votes')}
@@ -390,9 +392,9 @@ export const ProposalScreen = () => {
{showVoteResults &&
votingResults?.totalVotes.gt(new BN(0)) && (
{votingResults.results
?.sort((a, b) => b.percent - a.percent)
@@ -400,10 +402,10 @@ export const ProposalScreen = () => {
0 ? 's' : 'none'}
+ marginTop={idx > 0 ? '2' : 'none'}
>
@@ -412,8 +414,8 @@ export const ProposalScreen = () => {
@@ -429,13 +431,16 @@ export const ProposalScreen = () => {
justifyContent="space-between"
>
{humanReadable(r.weight, decimals)}
-
+
{r.percent.toFixed(2)}%
@@ -458,17 +463,17 @@ export const ProposalScreen = () => {
justifyContent="space-between"
alignItems="center"
flexGrow={1}
- backgroundColor="surfaceSecondary"
- borderRadius="l"
- padding="m"
- marginTop="m"
+ backgroundColor="bg.tertiary"
+ borderRadius="2xl"
+ padding="4"
+ marginTop="4"
>
-
+
{`${t('gov.votingPower.noPower')}, ${t(
'gov.votingPower.increase',
)}`}
-
+
>
@@ -479,12 +484,12 @@ export const ProposalScreen = () => {
-
+
{t('gov.proposals.toVote', {
maxChoicesPerVoter: proposal?.maxChoicesPerVoter,
choicesLength: proposal?.choices.length,
@@ -492,59 +497,66 @@ export const ProposalScreen = () => {
-
+
OR
-
+
{t('gov.proposals.assignProxy')}
}
- borderRadius="round"
- mt="m"
+ backgroundColor="primaryText"
+ titleColor="primaryBackground"
+ LeadingComponent={
+
+ }
+ borderRadius="full"
+ mt="4"
onPress={handleBrowseVoters}
- padding="s"
+ padding="2"
title={t('gov.assignProxy.browseVoters')}
/>
-
+
{showError && (
-
+
{showError}
)}
-
+
{votingResults.results?.map((r, index) => (
{
)}
-
+
diff --git a/src/features/governance/ProposalTags.tsx b/src/features/governance/ProposalTags.tsx
index 63213f153..77c715d07 100644
--- a/src/features/governance/ProposalTags.tsx
+++ b/src/features/governance/ProposalTags.tsx
@@ -11,17 +11,21 @@ export const ProposalTags: React.FC<{
? tags
.filter((tag) => tag !== 'tags')
.map((tag) => (
-
+
-
+
{tag.toUpperCase()}
diff --git a/src/features/governance/ProposalsList.tsx b/src/features/governance/ProposalsList.tsx
index aaf77ada9..1018f71c5 100644
--- a/src/features/governance/ProposalsList.tsx
+++ b/src/features/governance/ProposalsList.tsx
@@ -7,9 +7,9 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useOrganizationProposals } from '@helium/modular-governance-hooks'
import { useNavigation } from '@react-navigation/native'
import { BoxProps } from '@shopify/restyle'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useGovernance } from '@storage/GovernanceProvider'
-import { Theme } from '@theme/theme'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useGovernance } from '@config/storage/GovernanceProvider'
+import { Theme } from '@config/theme/theme'
import { getDerivedProposalState } from '@utils/governanceUtils'
import React, { useCallback, useMemo, useState } from 'react'
import { useAsync } from 'react-async-hook'
@@ -161,13 +161,13 @@ export const ProposalsList = ({ ...boxProps }: IProposalsListProps) => {
setFiltersOpen(true)}
>
-
+
{t('gov.proposals.filter', {
filter: filter.charAt(0).toUpperCase() + filter.slice(1),
})}
@@ -175,7 +175,7 @@ export const ProposalsList = ({ ...boxProps }: IProposalsListProps) => {
{isLoading ? (
-
+
) : (
proposals
?.filter((p) => Boolean(p.info))
@@ -183,7 +183,7 @@ export const ProposalsList = ({ ...boxProps }: IProposalsListProps) => {
0 ? 'm' : 'none'}
+ marginTop={idx > 0 ? '4' : 'none'}
proposal={proposal.info as ProposalV0}
proposalKey={proposal.publicKey}
onPress={async (m, p) =>
diff --git a/src/features/governance/ProposalsScreen.tsx b/src/features/governance/ProposalsScreen.tsx
index 9b5b69e15..a202613d6 100644
--- a/src/features/governance/ProposalsScreen.tsx
+++ b/src/features/governance/ProposalsScreen.tsx
@@ -1,6 +1,6 @@
import { useNavigation } from '@react-navigation/native'
import React from 'react'
-import { ScrollView } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
import GovernanceWrapper from './GovernanceWrapper'
import { ProposalsList } from './ProposalsList'
import { VotingPowerCard } from './VotingPowerCard'
@@ -11,18 +11,18 @@ export const ProposalsScreen = () => {
const selectedTab = 'proposals'
return (
-
-
- navigation.push('PositionsScreen', {
- mint: m.toBase58(),
- })
- }
- />
-
+
+
+
+ navigation.push('PositionsScreen', {
+ mint: m.toBase58(),
+ })
+ }
+ />
-
-
+
+
)
}
diff --git a/src/features/governance/ProxySearch.tsx b/src/features/governance/ProxySearch.tsx
index f8959702d..a8af52514 100644
--- a/src/features/governance/ProxySearch.tsx
+++ b/src/features/governance/ProxySearch.tsx
@@ -1,4 +1,4 @@
-import BrowseVoters from '@assets/images/browseVoters.svg'
+import BrowseVoters from '@assets/svgs/browseVoters.svg'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
@@ -9,13 +9,14 @@ import { proxiesQuery } from '@helium/voter-stake-registry-hooks'
import { EnhancedProxy } from '@helium/voter-stake-registry-sdk'
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 { shortenAddress } from '@utils/formatting'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList } from 'react-native'
import { useDebounce } from 'use-debounce'
+import { useColors } from '@config/theme/themeHooks'
import { GovernanceNavigationProp } from './governanceTypes'
export const ProxySearch: React.FC<{
@@ -27,6 +28,7 @@ export const ProxySearch: React.FC<{
const [focused, setFocused] = useState(false)
const [debouncedInput] = useDebounce(input, 300)
const { voteService, mint } = useGovernance()
+ const colors = useColors()
const {
data: resultPaged,
isLoading: loading,
@@ -61,16 +63,16 @@ export const ProxySearch: React.FC<{
({ item }: { item: { value: string; label: string } }) => {
return (
{
onValueChange(item.value)
setInput(item.value)
setFocused(false)
}}
>
-
+
{item.label}
@@ -115,7 +117,7 @@ export const ProxySearch: React.FC<{
renderItem={renderItem}
ListHeaderComponent={
<>
-
+
{selected ? selected.label : t('gov.assignProxy.searchPlaceholder')}
@@ -131,14 +133,16 @@ export const ProxySearch: React.FC<{
}}
/>
>
diff --git a/src/features/governance/RevokeProxyScreen.tsx b/src/features/governance/RevokeProxyScreen.tsx
index 0b57e8fca..250351a27 100644
--- a/src/features/governance/RevokeProxyScreen.tsx
+++ b/src/features/governance/RevokeProxyScreen.tsx
@@ -21,7 +21,7 @@ import {
import { usePublicKey } from '@hooks/usePublicKey'
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'
@@ -29,9 +29,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 {
@@ -82,7 +82,7 @@ export const RevokeProxyScreen = () => {
return (
{
setSelectedPositions((sel) => {
@@ -194,17 +194,17 @@ export const RevokeProxyScreen = () => {
-
-
+
+
{t('gov.revokeProxy.description')}
{/* If this view is for a singular position, do not show the set proxy wallet */}
-
+
{
{/* Don't show network when position already defined */}
{position ? null : (
-
-
+
+
{t('gov.assignProxy.selectNetwork')}
)}
-
+
{t('gov.revokeProxy.revokePositions')}
@@ -240,7 +242,7 @@ export const RevokeProxyScreen = () => {
: t('gov.assignProxy.selectAll')}
-
+
{error && (
@@ -248,9 +250,9 @@ export const RevokeProxyScreen = () => {
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
+ paddingTop="3"
>
-
+
{error.toString()}
@@ -258,20 +260,20 @@ export const RevokeProxyScreen = () => {
: undefined
+ isSubmitting ? : undefined
}
/>
diff --git a/src/features/governance/TransferTokensModal.tsx b/src/features/governance/TransferTokensModal.tsx
index 3154f3bb0..7be76d9a4 100644
--- a/src/features/governance/TransferTokensModal.tsx
+++ b/src/features/governance/TransferTokensModal.tsx
@@ -10,9 +10,9 @@ import { PositionWithMeta } from '@helium/voter-stake-registry-hooks'
import { PublicKey } from '@solana/web3.js'
import { useMint, useSolanaUnixNow } from '@helium/helium-react-hooks'
import { getMintMinAmountAsDecimal, precision } from '@utils/formatting'
-import { Keyboard, ScrollView } from 'react-native'
+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'
@@ -22,6 +22,7 @@ import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { getMinDurationFmt, getTimeLeftFromNowFmt } from '@utils/dateTools'
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { useTranslation } from 'react-i18next'
+import ScrollBox from '@components/ScrollBox'
const SOL_TXN_FEE = new BN(TXN_FEE_IN_LAMPORTS)
export const TransferTokensModal = ({
@@ -120,219 +121,235 @@ export const TransferTokensModal = ({
onClose={handleOnClose}
backgroundColor="transparent"
flex={1}
- padding="m"
- marginHorizontal="s"
+ padding="4"
+ marginHorizontal="2"
>
-
-
-
-
- {t('gov.transactions.transferPosition')}
+
+
+
+ {t('gov.transactions.transferPosition')}
+
+
+ {t('gov.positions.transferBlurb')}
+
+
+
+ {t('gov.positions.transferWarning')}
-
- {t('gov.positions.transferBlurb')}
-
-
-
- {t('gov.positions.transferWarning')}
+ {!hasTransferablePositions ? (
+
+ {t('gov.positions.cantTransfer')}
- {!hasTransferablePositions ? (
-
- {t('gov.positions.cantTransfer')}
-
- ) : (
-
- {t('gov.positions.transferLandrushWarning')}
-
- )}
-
- {hasTransferablePositions && (
- <>
-
-
-
- {t('gov.positions.amountToTransfer')}
-
-
- {amount || 'Amount (tokens)'}
-
-
-
-
+ ) : (
+
+ {t('gov.positions.transferLandrushWarning')}
+
+ )}
+
+ {hasTransferablePositions && (
+ <>
+
+
+
+ {t('gov.positions.amountToTransfer')}
+
- {t('gov.positions.selectTransfer')}
+ {amount || 'Amount (tokens)'}
-
- {positions.map((pos, idx) => {
- const { lockup } = pos
- const lockupKind = Object.keys(lockup.kind)[0] as string
- const isConstant = lockupKind === 'constant'
- const isSelected = selectedPosPk?.equals(pos.pubkey)
+
+
+
+
+ {t('gov.positions.selectTransfer')}
+
+
+ {positions.map((pos, idx) => {
+ const { lockup } = pos
+ const lockupKind = Object.keys(lockup.kind)[0] as string
+ const isConstant = lockupKind === 'constant'
+ const isSelected = selectedPosPk?.equals(pos.pubkey)
- return (
- 0 ? 'm' : 'none'}
+ return (
+ 0 ? '4' : 'none'}
+ flex={1}
+ borderRadius="2xl"
+ backgroundColor={
+ isSelected ? 'secondaryBackground' : 'bg.tertiary'
+ }
+ onPress={() => setSelectedPosPk(pos.pubkey)}
+ >
+ setSelectedPosPk(pos.pubkey)}
+ flexDirection="row"
+ padding="4"
+ justifyContent="space-between"
>
-
-
-
- {t('gov.positions.lockupType')}
-
-
- {isConstant ? 'Constant' : 'Decaying'}
-
-
-
-
-
-
- {t('gov.positions.voteMult')}
-
-
- {(
- (pos.votingPower.isZero()
- ? 0
- : // Mul by 100 to get 2 decimal places
- pos.votingPower
- .mul(new BN(100))
- .div(pos.amountDepositedNative)
- .toNumber() / 100) /
- (pos.genesisEnd.gt(new BN(unixNow))
- ? pos.votingMint
- .genesisVotePowerMultiplier
- : 1)
- ).toFixed(2)}
-
-
-
-
-
-
- {isConstant ? 'Min. Duration' : 'Time left'}
-
-
- {isConstant
- ? getMinDurationFmt(
- pos.lockup.startTs,
- pos.lockup.endTs,
- )
- : getTimeLeftFromNowFmt(pos.lockup.endTs)}
-
-
+
+
+ {t('gov.positions.lockupType')}
+
+
+ {isConstant ? 'Constant' : 'Decaying'}
+
-
- {t('gov.positions.lockedAmount', {
- amount:
- mintAcc &&
- humanReadable(
- new BN(pos.amountDepositedNative),
- mintAcc.decimals,
- ),
- symbol,
- })}
-
+
+
+ {t('gov.positions.voteMult')}
+
+
+ {(
+ (pos.votingPower.isZero()
+ ? 0
+ : // Mul by 100 to get 2 decimal places
+ pos.votingPower
+ .mul(new BN(100))
+ .div(pos.amountDepositedNative)
+ .toNumber() / 100) /
+ (pos.genesisEnd.gt(new BN(unixNow))
+ ? pos.votingMint.genesisVotePowerMultiplier
+ : 1)
+ ).toFixed(2)}
+
+
-
- )
- })}
- >
- )}
-
- {showError && (
-
-
- {showError}
-
-
+
+
+
+ {isConstant ? 'Min. Duration' : 'Time left'}
+
+
+ {isConstant
+ ? getMinDurationFmt(
+ pos.lockup.startTs,
+ pos.lockup.endTs,
+ )
+ : getTimeLeftFromNowFmt(pos.lockup.endTs)}
+
+
+
+
+
+
+ {t('gov.positions.lockedAmount', {
+ amount:
+ mintAcc &&
+ humanReadable(
+ new BN(pos.amountDepositedNative),
+ mintAcc.decimals,
+ ),
+ symbol,
+ })}
+
+
+
+ )
+ })}
+ >
)}
-
-
- : undefined
- }
- />
-
+ {showError && (
+
+
+ {showError}
+
+
+ )}
+
+
+ : undefined
+ }
+ />
+
+
)
}
diff --git a/src/features/governance/VoteHistory.tsx b/src/features/governance/VoteHistory.tsx
index 297102bae..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,15 +10,16 @@ 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'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, RefreshControl } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
import { ProposalTags } from './ProposalTags'
import { VoterCardStat } from './VoterCardStat'
import { GovernanceNavigationProp } from './governanceTypes'
@@ -74,15 +75,15 @@ export const VoteHistory: React.FC<{
return (
-
+
{t('gov.history.noneFound')}
@@ -107,13 +108,7 @@ export const VoteHistory: React.FC<{
const { primaryText } = useColors()
return (
-
}
- />
+ >
+
+
)
}
@@ -152,15 +156,15 @@ const ProposalItem: React.FC<{
return (
) : null}
@@ -181,24 +185,24 @@ const ProposalItem: React.FC<{
iconProps={{ width: 8, height: 8 }}
Icon={CancelledCircle}
color="black"
- textProps={{ variant: 'body3' }}
+ textProps={{ variant: 'textSmRegular' }}
text={t('gov.history.cancelled')}
/>
) : null}
- {proposal.name}
+ {proposal.name}
{timeExpired ? (
) : null}
-
+
{!timeExpired && (
{proposal.votes[0].weight ? (
<>
@@ -265,7 +269,7 @@ const ProposalItem: React.FC<{
>
) : (
) : (
-
+
)}
-
+
{option.name}
@@ -79,24 +79,24 @@ export const VoteOption = ({
flex={1}
borderTopColor="primaryBackground"
borderTopWidth={2}
- mt="ms"
- pt="s"
+ mt="3"
+ pt="2"
>
-
+
Voted by -
{voters.map((voter, idx) => (
<>
{idx !== voters.length - 1 && (
-
+
|
)}
@@ -112,7 +112,7 @@ export const VoteOption = ({
export const Voter = ({ voter }: { voter: PublicKey }) => {
const { knownProxy } = useKnownProxy(voter)
return (
-
+
{knownProxy?.name || shortenAddress(voter.toBase58())}
)
diff --git a/src/features/governance/VoterCardStat.tsx b/src/features/governance/VoterCardStat.tsx
index c87d53fac..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<
{
@@ -12,10 +12,10 @@ export const VoterCardStat: React.FC<
> = ({ title, value, ...boxProps }) => {
return (
-
+
{title}
-
+
{value}
diff --git a/src/features/governance/VoterScreen.tsx b/src/features/governance/VoterScreen.tsx
index 4e0802fc3..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,13 +11,14 @@ 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'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Image } from 'react-native'
+import ScrollBox from '@components/ScrollBox'
import { NetworkTabs } from './NetworkTabs'
import { VoteHistory } from './VoteHistory'
import { VoterCardStat } from './VoterCardStat'
@@ -93,178 +94,147 @@ export const VoterScreen = () => {
)
}
return (
-
-
-
-
-
-
- {proxy.name}
-
-
-
- {shortenAddress(proxy.wallet)}
+
+
+
+
+
+
+
+ {proxy.name}
- {[...(networks || new Set())].map((n) => {
- switch (n) {
- case 'mobile':
- return (
-
- )
- case 'hnt':
- return (
-
- )
- case 'iot':
- return (
-
- )
- }
- return null
- })}
+
+
+ {shortenAddress(proxy.wallet)}
+
+ {[...(networks || new Set())].map((n) => {
+ switch (n) {
+ case 'mobile':
+ return (
+
+ )
+ case 'hnt':
+ return (
+
+ )
+ case 'iot':
+ return (
+
+ )
+ }
+ return null
+ })}
+
-
-
-
-
-
-
- }
- backgroundColor="transparent"
- titleColor="white"
- borderColor="white"
- borderWidth={1}
- borderRadius="round"
- backgroundColorOpacityPressed={0.7}
- backgroundColorDisabled="black500"
- title={t('gov.voter.assignProxy')}
- disabled={!unproxiedPositions?.length}
- onPress={handleAssignProxy}
- />
- {proxiedPositions?.length ? (
- }
- backgroundColor="transparent"
- titleColor="white"
- borderColor="white"
- borderWidth={1}
- borderRadius="round"
- backgroundColorOpacityPressed={0.7}
- title={t('gov.voter.revokeProxy')}
- onPress={handleRevokeProxy}
- />
- ) : null}
-
-
-
-
-
-
-
-
-
+ }
+ backgroundColor="transparent"
+ titleColor="base.white"
+ borderColor="base.white"
+ borderWidth={1}
+ borderRadius="full"
+ backgroundColorOpacityPressed={0.7}
+ backgroundColorDisabled="gray.800"
+ title={t('gov.voter.assignProxy')}
+ disabled={!unproxiedPositions?.length}
+ onPress={handleAssignProxy}
/>
+ {proxiedPositions?.length ? (
+ }
+ backgroundColor="transparent"
+ titleColor="base.white"
+ borderColor="base.white"
+ borderWidth={1}
+ borderRadius="full"
+ backgroundColorOpacityPressed={0.7}
+ title={t('gov.voter.revokeProxy')}
+ onPress={handleRevokeProxy}
+ />
+ ) : null}
- {votingPower?.gt(new BN(0)) ? (
+
+
+
+
+
+ {
: ''
}
/>
+
+
+
- ) : null}
-
-
+ {votingPower?.gt(new BN(0)) ? (
+
+
+
+
+ ) : null}
+
+
-
-
-
- >
- }
- />
-
-
+
+
+
+ >
+ }
+ />
+
+
+
)
}
diff --git a/src/features/governance/VotersScreen.tsx b/src/features/governance/VotersScreen.tsx
index 0f0de9acd..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'
@@ -21,6 +21,7 @@ import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, Image, RefreshControl } from 'react-native'
import { useDebounce } from 'use-debounce'
+import ScrollBox from '@components/ScrollBox'
import { GovernanceNavigationProp } from './governanceTypes'
import { GovernanceWrapper } from './GovernanceWrapper'
import { VoterCardStat } from './VoterCardStat'
@@ -74,15 +75,15 @@ export default function VotersScreen() {
return (
-
+
{t('gov.voters.noneFound')}
@@ -110,10 +111,10 @@ export default function VotersScreen() {
return (
<>
-
+
{t('gov.voters.warning')}
@@ -132,16 +133,16 @@ export default function VotersScreen() {
if (renderBelowIndex > 0 && index === renderBelowIndex) {
return (
<>
-
-
+
+
-
+
{t('gov.voters.assignBelow')}
@@ -159,31 +160,40 @@ export default function VotersScreen() {
const { primaryText } = useColors()
return (
-
-
- {t('gov.voters.title')}
-
-
-
- }
- onEndReached={handleOnEndReached}
- />
-
+
+ }
+ >
+
+
+ {t('gov.voters.title')}
+
+
+
+
+
)
}
@@ -198,9 +208,9 @@ const VoterCard: React.FC<{
return (
{
navigation.navigate('VoterScreen', {
mint: mint.toBase58(),
@@ -210,25 +220,25 @@ const VoterCard: React.FC<{
>
-
- {proxy.name}
- {shortenAddress(proxy.wallet)}
+
+ {proxy.name}
+ {shortenAddress(proxy.wallet)}
-
+
) => {
-
+
{t('gov.votingPower.title')}
-
+
{t('gov.votingPower.locked', { symbol })}
@@ -64,10 +64,10 @@ export const VotingPowerCardSkeleton = (boxProps: BoxProps) => {
flex={1}
borderTopColor="primaryBackground"
borderTopWidth={2}
- paddingVertical="m"
- paddingHorizontal="m"
+ paddingVertical="4"
+ paddingHorizontal="4"
>
-
+
)
@@ -96,24 +96,24 @@ export const VotingPowerCard = ({
return (
<>
-
+
{!compact && (
-
+
{t('gov.votingPower.yourPower')}
-
+
>
)}
{!compact && noVotingPower && (
-
+
{t('gov.votingPower.noPower')}
@@ -122,11 +122,11 @@ export const VotingPowerCard = ({
<>
-
+
{t('gov.votingPower.title')}
-
+
{mintAcc &&
humanReadable(
votingPower || new BN(0),
@@ -141,16 +141,16 @@ export const VotingPowerCard = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- borderRadius="m"
- paddingHorizontal="s"
- paddingLeft="s"
+ borderRadius="2xl"
+ paddingHorizontal="2"
+ paddingLeft="2"
>
-
+
{`${
votingPower &&
amountLocked &&
@@ -167,10 +167,18 @@ export const VotingPowerCard = ({
-
+
{t('gov.votingPower.locked', { symbol })}
-
+
{mintAcc &&
humanReadable(
amountLocked || new BN(0),
@@ -185,10 +193,10 @@ export const VotingPowerCard = ({
-
+
{t('gov.votingPower.youHave', {
amount:
mintAcc &&
@@ -207,8 +215,8 @@ export const VotingPowerCard = ({
if (onPress)
return (
{renderCard(true)}
diff --git a/src/features/governance/governanceTypes.ts b/src/features/governance/governanceTypes.ts
index f4cd7004c..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]
@@ -36,18 +36,18 @@ const voteAccentColors = [] as Color[]
export default voteAccentColors
export const VotingResultColors: Color[] = [
- 'blueRibbon',
- 'aquaMarine',
- 'purple500',
- 'blueBright500',
- 'greenBright500',
- 'orange500',
- 'persianRose',
- 'gold',
- 'electricViolet',
- 'flamenco',
- 'malachite',
- 'turquoise',
- 'white',
- 'red500',
+ 'success.500',
+ 'error.500',
+ 'purple.500',
+ 'blue.light-500',
+ 'green.light-500',
+ 'orange.500',
+ 'pink.500',
+ 'yellow.500',
+ 'fuchsia.500',
+ 'orange.dark-500',
+ 'green.500',
+ 'cyan.500',
+ 'base.white',
+ 'fuchsia.500',
]
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/HomeNavigator.tsx b/src/features/home/HomeNavigator.tsx
deleted file mode 100644
index 736a7ad13..000000000
--- a/src/features/home/HomeNavigator.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import ConfirmPinScreen from '@components/ConfirmPinScreen'
-import {
- createStackNavigator,
- StackNavigationOptions,
-} from '@react-navigation/stack'
-import React, { memo } from 'react'
-import AccountsScreen from '../account/AccountsScreen'
-import AccountTokenScreen from '../account/AccountTokenScreen'
-import AirdropScreen from '../account/AirdropScreen'
-import AccountManageTokenListScreen from '../account/AccountManageTokenListScreen'
-import AddNewContact from '../addressBook/AddNewContact'
-import AddressBookNavigator from '../addressBook/AddressBookNavigator'
-import AddressQrScanner from '../addressBook/AddressQrScanner'
-import BurnScreen from '../burn/BurnScreen'
-import NotificationsNavigator from '../notifications/NotificationsNavigator'
-import AccountAssignScreen from '../onboarding/AccountAssignScreen'
-import ImportAccountNavigator from '../onboarding/import/ImportAccountNavigator'
-import PaymentQrScanner from '../payment/PaymentQrScanner'
-import PaymentScreen from '../payment/PaymentScreen'
-import RequestScreen from '../request/RequestScreen'
-import SettingsNavigator from '../settings/SettingsNavigator'
-import SwapNavigator from '../swaps/SwapNavigator'
-import AddNewAccountNavigator from './addNewAccount/AddNewAccountNavigator'
-import ImportSubAccountsScreen from '../onboarding/import/ImportSubAccountsScreen'
-import KeystoneAccountAssignScreen from '../keystone/KeystoneAccountAssignScreen'
-
-const HomeStack = createStackNavigator()
-
-const screenModalOptions = {
- presentation: 'modal',
-} as StackNavigationOptions
-
-const navigatorScreenOptions = {
- headerShown: false,
-} as StackNavigationOptions
-
-const HomeStackScreen = () => {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-export default memo(HomeStackScreen)
diff --git a/src/features/home/addNewAccount/AddNewAccountNavigator.tsx b/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
index 963ae932d..9e0b7e5d3 100644
--- a/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
+++ b/src/features/home/addNewAccount/AddNewAccountNavigator.tsx
@@ -1,8 +1,9 @@
-import React, { memo } from 'react'
+import React, { memo, useMemo } from 'react'
import {
createStackNavigator,
StackNavigationOptions,
} from '@react-navigation/stack'
+import { useColors } from '@config/theme/themeHooks'
import KeystoneNavigator from '../../keystone/KeystoneNavigator'
import AddNewAccountScreen from './AddNewAccountScreen'
import LedgerNavigator from '../../ledger/LedgerNavigator'
@@ -12,12 +13,18 @@ import CLIAccountNavigator from '../../onboarding/cli-import/CLIAccountNavigator
const AddAccountStack = createStackNavigator()
-const navigatorScreenOptions = {
- presentation: 'transparentModal',
- headerShown: false,
-} as StackNavigationOptions
-
const AddNewAccountNavigator = () => {
+ const colors = useColors()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ presentation: 'transparentModal',
+ headerShown: false,
+ cardStyle: { backgroundColor: colors.primaryBackground },
+ } as StackNavigationOptions),
+ [colors],
+ )
+
return (
{
{
}, [navigation])
return (
-
-
-
-
- {t('addNewAccount.title')}
-
+
+
+
+
-
-
-
-
- {selectedOption === 'create' && (
-
-
-
- )}
- {selectedOption === 'import' && (
-
-
-
- )}
- {selectedOption === 'ledger' && (
-
-
-
- )}
- {selectedOption === 'keystone' && (
-
-
-
- )}
-
-
-
+
+
+ {selectedOption === 'create' && (
+
+
+
+ )}
+ {selectedOption === 'import' && (
+
+
+
+ )}
+ {selectedOption === 'ledger' && (
+
+
+
+ )}
+ {selectedOption === 'keystone' && (
+
+
+
+ )}
+
+
+
+
)
}
diff --git a/src/features/home/homeTypes.ts b/src/features/home/homeTypes.ts
deleted file mode 100644
index 599746ab3..000000000
--- a/src/features/home/homeTypes.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { StackNavigationProp } from '@react-navigation/stack'
-import { RouteAccount } from '../onboarding/create/createAccountNavTypes'
-
-export type PaymentRouteParam = {
- payer?: string
- payments?: string
- payee?: string
- amount?: string
- memo?: string
- netType?: string
- defaultTokenType?: string
- mint?: string
-}
-
-export type BurnRouteParam = {
- address: string
- amount?: string
- memo?: string
- isDelegate?: boolean
- mint?: string
-}
-
-export type HomeStackParamList = {
- AccountsScreen: undefined
- AccountManageTokenListScreen: undefined
- AccountTokenScreen: { mint: string }
- AccountAssignScreen: undefined | RouteAccount
- KeystoneAccountAssignScreen: undefined
- ConfirmPin: {
- action: 'payment'
- }
- PaymentScreen: undefined | PaymentRouteParam
- AirdropScreen: { mint: string }
- BurnScreen: BurnRouteParam
- PaymentQrScanner: undefined
- RequestScreen: undefined
- OnboardData: undefined
- AddressBookNavigator: undefined
- NotificationsNavigator: undefined
- SettingsNavigator: undefined
- AddNewContact: undefined
- AddNewAccountNavigator: undefined
- SwapNavigator: undefined
- ReImportAccountNavigator:
- | undefined
- | {
- screen: 'AccountImportScreen'
- params: {
- restoringAccount?: boolean
- accountAddress?: string
- }
- }
- VoteNavigator: undefined
-}
-
-export type HomeNavigationProp = StackNavigationProp
diff --git a/src/features/hotspot-onboarding/OnboardingNav.tsx b/src/features/hotspot-onboarding/OnboardingNav.tsx
deleted file mode 100644
index acad47ca3..000000000
--- a/src/features/hotspot-onboarding/OnboardingNav.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import {
- createNativeStackNavigator,
- NativeStackNavigationOptions,
-} from '@react-navigation/native-stack'
-import * as React from 'react'
-import HotspotBLENav from './iot-ble/HotspotBLENav'
-import SelectDevice from './SelectDevice'
-
-const Stack = createNativeStackNavigator()
-
-const screenOptions = { headerShown: false } as NativeStackNavigationOptions
-
-export default React.memo(function OnboardingNav() {
- 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 f79ff4a13..000000000
--- a/src/features/hotspot-onboarding/SelectDevice.tsx
+++ /dev/null
@@ -1,87 +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="s"
- flexDirection="row"
- borderTopWidth={index === 0 ? 0 : 1}
- borderColor="grey900"
- 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 d6193c5bf..000000000
--- a/src/features/hotspot-onboarding/iot-ble/HotspotBLENav.tsx
+++ /dev/null
@@ -1,63 +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 { 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()
-
-const screenOptions = { headerShown: false } as NativeStackNavigationOptions
-
-type Route = RouteProp
-export default React.memo(function HotspotBLENav() {
- const route = useRoute()
- const iotParams = route.params
- 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 4e46c950b..000000000
--- a/src/features/hotspot-onboarding/iot-ble/ScanHotspots.tsx
+++ /dev/null
@@ -1,252 +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 c5d9873f3..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('CollectablesTopTab')
- }
-
- 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="l"
- flexDirection="row"
- borderTopWidth={index === 0 ? 0 : 1}
- borderColor="grey900"
- 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 8165b6d10..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 833f95576..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 57%
rename from src/features/hotspot-onboarding/iot-ble/AddGatewayBle.tsx
rename to src/features/hotspot-onboarding/screens/iot/AddToWalletScreen.tsx
index aa6f2bd47..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('hotspotOnboarding.onboarding.subtitle', {
- network,
- })}
+ {t('AddToWalletScreen.title')}
+
+ {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,11 +493,16 @@ const AddGatewayBle = () => {
.join(' and ')}`,
})}
-
+
{t('hotspotOnboarding.onboarding.twoSolutions')}
{
{selectedOption === 'contact' && (
{
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')}
)}
@@ -407,54 +571,68 @@ const AddGatewayBle = () => {
<>
{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 86%
rename from src/features/collectables/AntennaSetupScreen.tsx
rename to src/features/hotspots/AntennaSetupScreen.tsx
index ba71bce52..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'
@@ -36,7 +36,6 @@ const AntennaSetupScreen = () => {
const entityKey = useEntityKey(collectable)
const iotInfoAcc = useIotInfo(entityKey)
const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
- const backEdges = useMemo(() => ['top'] as Edge[], [])
const [hasSetDefaults, setHasSetDefaults] = useState(false)
const [gain, setGain] = useState()
const [elevation, setElevation] = useState()
@@ -104,10 +103,10 @@ const AntennaSetupScreen = () => {
return (
Keyboard.dismiss()}>
@@ -115,25 +114,29 @@ const AntennaSetupScreen = () => {
edges={safeEdges}
backgroundColor="transparent"
flex={1}
- padding="m"
- marginHorizontal="s"
+ padding="4"
+ marginHorizontal="2"
marginVertical="xs"
>
-
+
{t('antennaSetupScreen.antennaSetup')}
{t('antennaSetupScreen.antennaSetupDescription')}
{
keyboardType: 'decimal-pad',
}}
/>
-
+
{
flexDirection="row"
justifyContent="center"
alignItems="center"
- marginVertical="s"
+ marginVertical="2"
minHeight={40}
>
{showError && (
-
+
{showError}
)}
@@ -178,18 +185,15 @@ const AntennaSetupScreen = () => {
+
) : undefined
}
/>
diff --git a/src/features/collectables/AssertLocationScreen.tsx b/src/features/hotspots/AssertLocationScreen.tsx
similarity index 71%
rename from src/features/collectables/AssertLocationScreen.tsx
rename to src/features/hotspots/AssertLocationScreen.tsx
index a2a23b6bf..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,13 +11,9 @@ import {
ImageBox,
ReAnimatedBlurBox,
ReAnimatedBox,
- SafeAreaBox,
- 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'
@@ -32,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'
@@ -53,28 +47,43 @@ import {
KeyboardAvoidingView,
TouchableWithoutFeedback,
} from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
import 'text-encoding-polyfill'
import { useDebounce } from 'use-debounce'
-import { useColors, useCreateOpacity } from '@theme/themeHooks'
+import { useColors, useCreateOpacity } from '@config/theme/themeHooks'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+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 route = useRoute()
const { backgroundStyle } = useCreateOpacity()
const { collectable } = route.params
const entityKey = useEntityKey(collectable)
const { info: iotInfoAcc } = useIotInfo(entityKey)
const { info: mobileInfoAcc } = useMobileInfo(entityKey)
- const backEdges = useMemo(() => ['top'] as Edge[], [])
- 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()
@@ -89,6 +98,7 @@ const AssertLocationScreen = () => {
const forwardGeo = useForwardGeo()
const { submitUpdateEntityInfo } = useSubmitTxn()
const navigation = useNavigation()
+
const {
maker,
makerDc,
@@ -130,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],
@@ -251,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])
@@ -406,17 +419,21 @@ const AssertLocationScreen = () => {
[loadingMyDc, loadingMakerDc, loadingLocationAssertDcRequirements],
)
+ const onBack = useCallback(() => {
+ navigation.goBack()
+ }, [navigation])
+
const [debouncedDisabled] = useDebounce(disabled, 300)
const [reverseGeoLoading] = useDebounce(reverseGeo.loading, 300)
return (
-
+
@@ -430,96 +447,107 @@ const AssertLocationScreen = () => {
zIndex={isLoading ? 100 : 0}
>
-
+
- navigation.goBack()}
- >
-
-
- Back
-
-
+
{
flexDirection="row"
justifyContent="space-between"
position="absolute"
- marginHorizontal="ms"
+ marginHorizontal="3"
width="100%"
bottom={20}
>
@@ -542,19 +570,19 @@ const AssertLocationScreen = () => {
flexShrink={1}
flexDirection="row"
alignItems="center"
- marginHorizontal="ms"
+ marginHorizontal="3"
>
{reverseGeoLoading && (
)}
{showError && (
-
+
{showError}
)}
@@ -562,17 +590,17 @@ const AssertLocationScreen = () => {
{reverseGeo.result}
@@ -586,14 +614,14 @@ const AssertLocationScreen = () => {
flexDirection="row"
alignItems="center"
justifyContent="flex-end"
- marginHorizontal="ms"
+ marginHorizontal="3"
>
{
/>
{
) : (
-
+
+
+
)}
{!searchVisible && (
-
+
{
{metadata?.name && (
@@ -662,21 +691,25 @@ const AssertLocationScreen = () => {
)}
-
+
IOT:
-
+
-
+
{t('assertLocationScreen.mobileTitle')}:
@@ -684,7 +717,9 @@ const AssertLocationScreen = () => {
width={16}
height={16}
color={
- mobileLocation ? colors.blueBright500 : colors.darkGrey
+ mobileLocation
+ ? colors['blue.light-500']
+ : colors['gray.700']
}
/>
@@ -693,22 +728,25 @@ const AssertLocationScreen = () => {
{debouncedDisabled || asserting ? (
-
+
) : (
{t('assertLocationScreen.title')}
@@ -717,7 +755,8 @@ const AssertLocationScreen = () => {
)}
{elevGainVisible ? (
- {
bottom={0}
height="100%"
width="100%"
+ paddingHorizontal="xl"
>
Keyboard.dismiss()}>
+
+ setElevGainVisible(false)}
+ />
+
+
{t('assertLocationScreen.antennaSetup')}
{t('assertLocationScreen.antennaSetupDescription')}
{
}}
/>
{
-
+
-
+
) : undefined}
-
+
)
}
diff --git a/src/features/collectables/ChangeRewardsRecipientScreen.tsx b/src/features/hotspots/ChangeRewardsRecipientScreen.tsx
similarity index 70%
rename from src/features/collectables/ChangeRewardsRecipientScreen.tsx
rename to src/features/hotspots/ChangeRewardsRecipientScreen.tsx
index 1bfaef5db..a2bcac50c 100644
--- a/src/features/collectables/ChangeRewardsRecipientScreen.tsx
+++ b/src/features/hotspots/ChangeRewardsRecipientScreen.tsx
@@ -1,4 +1,4 @@
-import Menu from '@assets/images/menu.svg'
+import Menu from '@assets/svgs/menu.svg'
import AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
@@ -8,14 +8,13 @@ import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
import { DelayedFadeIn } from '@components/FadeInOut'
-import IotSymbol from '@assets/images/iotSymbol.svg'
-import MobileSymbol from '@assets/images/mobileSymbol.svg'
-import SafeAreaBox from '@components/SafeAreaBox'
+import IotSymbol from '@assets/svgs/iotSymbol.svg'
+import MobileSymbol from '@assets/svgs/mobileSymbol.svg'
import Text from '@components/Text'
import TextInput from '@components/TextInput'
import useSubmitTxn from '@hooks/useSubmitTxn'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
-import { CSAccount } from '@storage/cloudStorage'
+import { CSAccount } from '@config/storage/cloudStorage'
import { ellipsizeAddress, solAddressIsValid } from '@utils/accountUtils'
import React, { memo, useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -26,17 +25,18 @@ import {
TextInputEndEditingEventData,
TouchableWithoutFeedback,
} from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { IOT_LAZY_KEY, MOBILE_LAZY_KEY } from '@utils/constants'
import { PublicKey } from '@solana/web3.js'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { useCurrentWallet } from '@hooks/useCurrentWallet'
-import { useColors } from '@theme/themeHooks'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import ScrollBox from '@components/ScrollBox'
import * as Logger from '../../utils/logger'
import {
CollectableNavigationProp,
CollectableStackParamList,
-} from './collectablesTypes'
+} from './hotspotTypes'
import { Mints } from '../../utils/constants'
type Route = RouteProp<
@@ -46,12 +46,12 @@ type Route = RouteProp<
const ChangeRewardsRecipientScreen = () => {
const { t } = useTranslation()
const colors = useColors()
+ const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
const route = useRoute()
const nav = useNavigation()
const wallet = useCurrentWallet()
const { hotspot } = route.params
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
- const backEdges = useMemo(() => ['top'] as Edge[], [])
const addressBookRef = useRef(null)
const [recipient, setRecipient] = useState('')
const [recipientName, setRecipientName] = useState('')
@@ -177,45 +177,44 @@ const ChangeRewardsRecipientScreen = () => {
return (
-
-
+
Keyboard.dismiss()}>
-
{t('changeRewardsRecipientScreen.title')}
-
+
{t('changeRewardsRecipientScreen.description')}
-
+
{t('changeRewardsRecipientScreen.blurb')}
@@ -225,7 +224,7 @@ const ChangeRewardsRecipientScreen = () => {
{!recipientsAreDifferent ? (
<>
@@ -240,9 +239,9 @@ const ChangeRewardsRecipientScreen = () => {
@@ -267,9 +266,11 @@ const ChangeRewardsRecipientScreen = () => {
height={20}
/>
)}
- Recipient
+
+ Recipient
+
-
+
{ellipsizeAddress(
new PublicKey(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
@@ -284,7 +285,7 @@ const ChangeRewardsRecipientScreen = () => {
) : (
{
{hasIotRecipient && (
@@ -310,9 +311,11 @@ const ChangeRewardsRecipientScreen = () => {
width={20}
height={20}
/>
- Recipient
+
+ Recipient
+
-
+
{ellipsizeAddress(
new PublicKey(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
@@ -325,9 +328,9 @@ const ChangeRewardsRecipientScreen = () => {
{hasMobileRecipient && (
@@ -344,9 +347,11 @@ const ChangeRewardsRecipientScreen = () => {
width={20}
height={20}
/>
- Recipient
+
+ Recipient
+
-
+
{ellipsizeAddress(
new PublicKey(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
@@ -362,102 +367,117 @@ const ChangeRewardsRecipientScreen = () => {
flexDirection="row"
justifyContent="space-between"
alignItems="center"
- borderRadius="m"
- paddingVertical="sx"
- marginLeft="s"
- paddingLeft="s"
- paddingRight="s"
- backgroundColor="black600"
+ borderRadius="2xl"
+ paddingVertical="1.5"
+ marginLeft="2"
+ paddingLeft="2"
+ paddingRight="2"
+ backgroundColor="cardBackground"
onPress={handleRemoveRecipient}
>
{removing ? (
-
+
) : (
-
+
{t('generic.remove')}
)}
)}
-
-
+
+
+
+
{t('changeRewardsRecipientScreen.warning')}
-
+
-
-
- {showError && (
-
- {showError}
-
- )}
-
-
- {} : handleUpdateRecipient}
- TrailingComponent={
- updating ? (
-
- ) : undefined
- }
- />
-
-
+
+ {showError && (
+
+ {showError}
+
+ )}
+
+
+ {} : handleUpdateRecipient}
+ TrailingComponent={
+ updating ? (
+
+ ) : undefined
+ }
+ style={{
+ marginBottom: bottom + spacing[1],
+ }}
+ />
+
+
+
+
)
}
diff --git a/src/features/collectables/ClaimAllRewardsScreen.tsx b/src/features/hotspots/ClaimAllRewardsScreen.tsx
similarity index 86%
rename from src/features/collectables/ClaimAllRewardsScreen.tsx
rename to src/features/hotspots/ClaimAllRewardsScreen.tsx
index b53486d7e..78bc01c55 100644
--- a/src/features/collectables/ClaimAllRewardsScreen.tsx
+++ b/src/features/hotspots/ClaimAllRewardsScreen.tsx
@@ -13,7 +13,7 @@ import { useCurrentWallet } from '@hooks/useCurrentWallet'
import useHotspots from '@hooks/useHotspots'
import useSubmitTxn from '@hooks/useSubmitTxn'
import { useNavigation } from '@react-navigation/native'
-import { useModal } from '@storage/ModalsProvider'
+import { useModal } from '@config/storage/ModalsProvider'
import {
IOT_LAZY_KEY,
MIN_BALANCE_THRESHOLD,
@@ -22,7 +22,7 @@ import {
import BN from 'bn.js'
import React, { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { CollectableNavigationProp } from './collectablesTypes'
+import { CollectableNavigationProp } from './hotspotTypes'
const ClaimAllRewardsScreen = () => {
const { t } = useTranslation()
@@ -103,15 +103,15 @@ const ClaimAllRewardsScreen = () => {
entering={DelayedFadeIn}
backgroundColor="primaryBackground"
>
-
+
-
+
{subtitle}
-
+
{t('collectablesScreen.hotspots.hotspotsClaimMessage')}
@@ -126,7 +126,7 @@ const ClaimAllRewardsScreen = () => {
) : null}
@@ -135,7 +135,7 @@ const ClaimAllRewardsScreen = () => {
) : null}
@@ -143,9 +143,9 @@ const ClaimAllRewardsScreen = () => {
{claimError && (
@@ -155,23 +155,22 @@ const ClaimAllRewardsScreen = () => {
)}
+
) : undefined
}
/>
diff --git a/src/features/collectables/ClaimRewardsScreen.tsx b/src/features/hotspots/ClaimRewardsScreen.tsx
similarity index 88%
rename from src/features/collectables/ClaimRewardsScreen.tsx
rename to src/features/hotspots/ClaimRewardsScreen.tsx
index 992646a0c..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
@@ -113,18 +113,18 @@ const ClaimRewardsScreen = () => {
-
+
{subtitle}
-
+
{t('collectablesScreen.hotspots.hotspotClaimMessage')}
@@ -138,7 +138,7 @@ const ClaimRewardsScreen = () => {
)}
@@ -146,7 +146,7 @@ const ClaimRewardsScreen = () => {
)}
@@ -154,9 +154,9 @@ const ClaimRewardsScreen = () => {
{claimError && (
@@ -166,23 +166,23 @@ const ClaimRewardsScreen = () => {
)}
+
) : undefined
}
/>
diff --git a/src/features/collectables/ClaimingRewardsScreen.tsx b/src/features/hotspots/ClaimingRewardsScreen.tsx
similarity index 78%
rename from src/features/collectables/ClaimingRewardsScreen.tsx
rename to src/features/hotspots/ClaimingRewardsScreen.tsx
index c9bc85b5f..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,8 +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 { TabBarNavigationProp } from '../../navigation/rootTypes'
-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'
@@ -31,7 +32,8 @@ import mobileTokens from './animations/mobile-tokens.json'
const ClaimingRewardsScreen = () => {
const { currentAccount } = useAccountStorage()
- const navigation = useNavigation()
+ const colors = useColors()
+ const navigation = useNavigation()
const wallet = useCurrentWallet()
const solBalance = useBN(useSolOwnedAmount(wallet).amount)
const { bottom } = useSafeAreaInsets()
@@ -58,7 +60,7 @@ const ClaimingRewardsScreen = () => {
// Reset Collectables stack to first screen
navigation.reset({
index: 0,
- routes: [{ name: 'Collectables' }],
+ routes: [{ name: 'Hotspot' }],
})
}, [navigation])
@@ -78,7 +80,11 @@ const ClaimingRewardsScreen = () => {
}
return (
-
+
{
>
{
entering={FadeIn}
exiting={FadeOut}
>
-
+
{t('collectablesScreen.claimComplete')}
@@ -125,14 +131,18 @@ const ClaimingRewardsScreen = () => {
entering={FadeIn}
exiting={FadeOut}
>
-
-
+
+
{t('collectablesScreen.rewardsError')}
@@ -151,12 +161,12 @@ const ClaimingRewardsScreen = () => {
entering={FadeIn}
exiting={FadeOut}
>
-
+
{t('collectablesScreen.rewardsError')}
@@ -170,15 +180,19 @@ const ClaimingRewardsScreen = () => {
entering={FadeIn}
exiting={FadeOut}
>
-
-
+
+
{t('collectablesScreen.claimingRewards')}
{t('collectablesScreen.claimingRewardsBody')}
@@ -188,8 +202,8 @@ const ClaimingRewardsScreen = () => {
{typeof solanaPayment.progress !== 'undefined' ? (
{
{solanaPayment.progress.text}
) : (
-
+
)}
) : (
@@ -242,19 +256,20 @@ const ClaimingRewardsScreen = () => {
style={{ marginBottom: bottom }}
>
+
}
/>
diff --git a/src/features/hotspot-onboarding/iot-ble/Diagnostics.tsx b/src/features/hotspots/Diagnostics.tsx
similarity index 78%
rename from src/features/hotspot-onboarding/iot-ble/Diagnostics.tsx
rename to src/features/hotspots/Diagnostics.tsx
index 5dc318f47..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()
@@ -41,46 +40,46 @@ const Diagnostics = () => {
key={key}
flexDirection="row"
justifyContent="space-between"
- mb="s"
- pb="s"
- borderColor="grey900"
+ mb="2"
+ pb="2"
+ borderColor="gray.900"
borderBottomWidth={1}
>
-
+
{key}
-
+
{JSON.stringify(value)}
))}
{!diagnosticInfo && !loading && (
-
+
{t('hotspotOnboarding.diagnostics.noneFound')}
)}
: undefined}
/>
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 84%
rename from src/features/collectables/HotspotMapHotspotDetails.tsx
rename to src/features/hotspots/HotspotMapHotspotDetails.tsx
index a0adc12ac..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'
@@ -40,10 +40,11 @@ import { useAsyncCallback } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import { Alert, AlertButton, Linking } from 'react-native'
import { SvgUri } from 'react-native-svg'
-import { useSolana } from '../../solana/SolanaProvider'
+import SafeAreaBox from '@components/SafeAreaBox'
+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,
@@ -57,40 +58,40 @@ const IotMapDetails = ({
const { gain, elevation } = info
return (
-
+
-
+
{t('collectablesScreen.hotspots.map.transmitScale')}
-
-
+
+
---
-
+
{t('generic.maker')}
-
+
{maker}
-
+
{t('generic.gain')}
-
+
{gain ? gain / 10 : gain} {t('generic.dBi')}
-
+
{t('generic.elevation')}
- {elevation}m
+ {elevation}m
@@ -109,24 +110,24 @@ const MobileMapDetails = ({
const { deviceType } = info
return (
-
+
- {t('generic.coverage')}
+ {t('generic.coverage')}
-
-
+
+
---
- {t('generic.maker')}
- {maker}
+ {t('generic.maker')}
+ {maker}
- {t('generic.radioType')}
-
+ {t('generic.radioType')}
+
{deviceType ? Object.keys(deviceType)[0] : '---'}
@@ -170,7 +171,7 @@ export const HotspotMapHotspotDetails = ({
)?.group_value
const collectionKey = usePublicKey(collection)
const { primaryText } = useColors()
- const { backgroundStyle: flamecoOpaque } = useOpacity('flamenco', 0.1)
+ const { backgroundStyle: flamecoOpaque } = useOpacity('orange.500', 0.1)
const { loading: mplxLoading, metadata: mplxMetadata } =
useMetaplexMetadata(collectionKey)
@@ -447,8 +448,12 @@ export const HotspotMapHotspotDetails = ({
})
return (
- <>
-
+
+
{isLoading && (
-
+
)}
@@ -465,10 +470,10 @@ export const HotspotMapHotspotDetails = ({
<>
@@ -491,16 +496,16 @@ export const HotspotMapHotspotDetails = ({
{streetAddress && (
<>
-
+
{streetAddress}
>
)}
@@ -510,7 +515,11 @@ export const HotspotMapHotspotDetails = ({
alignItems="center"
onPress={handleCopyAddress}
>
-
+
{ellipsizeAddress(eccCompact, { numChars: 4 })}
@@ -536,9 +545,9 @@ export const HotspotMapHotspotDetails = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
+ paddingTop="3"
>
-
+
{onboardError.toString()}
@@ -559,20 +568,20 @@ export const HotspotMapHotspotDetails = ({
alignItems="center"
zIndex={100}
>
-
+
{selectExplorerOpen ? (
<>
-
+
{t('activityScreen.selectExplorer')}
-
+
{t('activityScreen.selectExplorerSubtitle')}
@@ -580,6 +589,7 @@ export const HotspotMapHotspotDetails = ({
{available?.map((a) => {
return (
@@ -613,9 +623,9 @@ export const HotspotMapHotspotDetails = ({
flex={1}
flexDirection="row"
alignItems="center"
- marginHorizontal="m"
+ marginHorizontal="4"
>
-
+
{t('collectablesScreen.hotspots.claimRewards')}
{pendingMobileRewardsString}
@@ -657,10 +667,10 @@ export const HotspotMapHotspotDetails = ({
justifyContent="space-between"
alignItems="center"
backgroundColor="iotDarkGreen"
- borderRadius="m"
+ borderRadius="2xl"
paddingVertical="xs"
paddingLeft="xs"
- paddingRight="s"
+ paddingRight="2"
>
{pendingIotRewardsString}
@@ -680,19 +690,19 @@ export const HotspotMapHotspotDetails = ({
-
+
{t('changeRewardsRecipientScreen.title')}
{hasRecipientSet && (
@@ -701,15 +711,15 @@ export const HotspotMapHotspotDetails = ({
flexDirection="row"
justifyContent="space-between"
alignItems="center"
- borderRadius="m"
- paddingVertical="sx"
- paddingLeft="s"
- paddingRight="s"
+ borderRadius="2xl"
+ paddingVertical="1.5"
+ paddingLeft="2"
+ paddingRight="2"
style={{
...flamecoOpaque,
}}
>
-
+
{t('changeRewardsRecipientScreen.set')}
@@ -757,6 +767,6 @@ export const HotspotMapHotspotDetails = ({
)}
)}
- >
+
)
}
diff --git a/src/features/collectables/HotspotMapLegend.tsx b/src/features/hotspots/HotspotMapLegend.tsx
similarity index 63%
rename from src/features/collectables/HotspotMapLegend.tsx
rename to src/features/hotspots/HotspotMapLegend.tsx
index 01a0b1c27..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 = ({
@@ -16,13 +16,13 @@ export const HotspotMapLegend = ({
flexDirection="column"
justifyContent="center"
alignItems="center"
- paddingTop="ms"
- paddingBottom="m"
+ paddingTop="3"
+ paddingBottom="4"
>
-
+
{network} Hotspot
@@ -51,11 +51,11 @@ export const HotspotMapLegend = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingRight="ms"
- paddingLeft="s"
- paddingVertical="sx"
- borderRadius="round"
- backgroundColor="darkGrey"
+ paddingRight="3"
+ paddingLeft="2"
+ paddingVertical="1.5"
+ borderRadius="full"
+ backgroundColor="gray.700"
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
gap={6}
@@ -68,10 +68,14 @@ export const HotspotMapLegend = ({
-
+
Low Boost
@@ -80,8 +84,12 @@ export const HotspotMapLegend = ({
justifyContent="center"
alignItems="center"
>
-
-
+
+
High Boost
@@ -91,11 +99,11 @@ export const HotspotMapLegend = ({
flexDirection="row"
justifyContent="center"
alignItems="center"
- paddingRight="ms"
- paddingLeft="s"
- paddingVertical="sx"
- borderRadius="round"
- backgroundColor="darkGrey"
+ paddingRight="3"
+ paddingLeft="2"
+ paddingVertical="1.5"
+ borderRadius="full"
+ backgroundColor="gray.700"
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
gap={8}
@@ -107,13 +115,13 @@ export const HotspotMapLegend = ({
color={colors.solanaPurple}
opacity={0.6}
/>
-
+
Weak Signal
-
+
Strong Signal
diff --git a/src/features/hotspots/HotspotMapScreen.tsx b/src/features/hotspots/HotspotMapScreen.tsx
new file mode 100644
index 000000000..4200b77c2
--- /dev/null
+++ b/src/features/hotspots/HotspotMapScreen.tsx
@@ -0,0 +1,577 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+/* eslint-disable no-restricted-properties */
+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'
+import FabButton from '@components/FabButton'
+import { DelayedFadeIn } from '@components/FadeInOut'
+import Text from '@components/Text'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import {
+ BottomSheetModal,
+ BottomSheetModalProvider,
+ BottomSheetScrollView,
+} from '@gorhom/bottom-sheet'
+import {
+ decodeEntityKey,
+ init,
+ iotInfoKey,
+ keyToAssetForAsset,
+ mobileInfoKey,
+} from '@helium/helium-entity-manager-sdk'
+import { chunks, truthy } from '@helium/spl-utils'
+import useHotspots from '@hooks/useHotspots'
+import { IotHotspotInfoV0 } from '@hooks/useIotInfo'
+import { MobileHotspotInfoV0 } from '@hooks/useMobileInfo'
+import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
+import { useBackgroundStyle, useColors } from '@config/theme/themeHooks'
+import { IOT_CONFIG_KEY, MOBILE_CONFIG_KEY } from '@utils/constants'
+import {
+ getCachedIotInfos,
+ getCachedKeyToAssets,
+ getCachedMobileInfos,
+ toAsset,
+} from '@utils/solanaUtils'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useAsync } from 'react-async-hook'
+import { useTranslation } from 'react-i18next'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { HotspotWithPendingRewards } from '../../types/solana'
+import { HotspotMapHotspotDetails } from './HotspotMapHotspotDetails'
+import { HotspotMapLegend } from './HotspotMapLegend'
+import {
+ CollectableNavigationProp,
+ CollectableStackParamList,
+} 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()
+ const route = useRoute()
+ const bottomSheetStyle = useBackgroundStyle('bg.tertiary')
+ const navigation = useNavigation()
+ const colors = useColors()
+ // const mapRef = useRef(null)
+ // const cameraRef = useRef(null)
+ const bottomSheetRef = useRef(null)
+ const [bottomSheetSnapIndex, setBottomSheetSnapIndex] = useState(-1)
+ // 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',
+ )
+ const [loadingInfos, setLoadingInfos] = useState(false)
+ const [hexInfoBuckets, setHexInfoBuckets] = useState<{
+ [key: string]: IotHotspotInfoV0[] | MobileHotspotInfoV0[]
+ }>({})
+ const [activeHex, setActiveHex] = useState()
+ 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])
+
+ // - fetch all hotspots
+ useEffect(() => {
+ if (!loading && !onEndReached) {
+ fetchAll()
+ }
+ }, [loading, onEndReached, fetchAll])
+
+ // - fetch infos by networkType for all hotspots
+ // - setUp hexInfoBuckets
+ useAsync(async () => {
+ if (onEndReached && anchorProvider) {
+ setLoadingInfos(true)
+ const hemProgram = await init(anchorProvider)
+
+ const infos = (
+ await Promise.all(
+ chunks(hotspots, 100).map(async (chunk) => {
+ const keyToAssetKeys = chunk.map((h) =>
+ keyToAssetForAsset(toAsset(h)),
+ )
+
+ const ktaAccs = await getCachedKeyToAssets(
+ hemProgram,
+ keyToAssetKeys,
+ )
+
+ const entityKeys = ktaAccs
+ .map((kta) => {
+ return decodeEntityKey(kta.entityKey, kta.keySerialization)
+ })
+ .filter(truthy)
+
+ const infoKeys = entityKeys.map((ek) => {
+ const keys = {
+ IOT: iotInfoKey(IOT_CONFIG_KEY, ek)[0],
+ MOBILE: mobileInfoKey(MOBILE_CONFIG_KEY, ek)[0],
+ }
+
+ return keys[networkType]
+ })
+
+ if (networkType === 'IOT') {
+ return getCachedIotInfos(hemProgram, infoKeys)
+ }
+
+ if (networkType === 'MOBILE') {
+ return getCachedMobileInfos(hemProgram, infoKeys)
+ }
+ }),
+ )
+ ).flat()
+
+ const infoBuckets = infos
+ .filter((info) => info && truthy(info.location))
+ .reduce(
+ (acc, info) => ({
+ ...acc,
+ ...(info?.location
+ ? {
+ [info.location.toString()]: [
+ ...(acc[info.location.toString()] || []),
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ info as any,
+ ],
+ }
+ : {}),
+ }),
+ {} as {
+ [key: string]: IotHotspotInfoV0[] | MobileHotspotInfoV0[]
+ },
+ )
+
+ setHexInfoBuckets(infoBuckets)
+ setLoadingInfos(false)
+ }
+ }, [
+ onEndReached,
+ anchorProvider,
+ networkType,
+ hotspots,
+ setLoadingInfos,
+ setHexInfoBuckets,
+ ])
+
+ useAsync(async () => {
+ // if hotspot is provided, check if it's IOT or MOBILE
+ // scope networkType to the hotspot's network type
+ if (hotspot) {
+ if (onEndReached && !loadingInfos && anchorProvider) {
+ const [hex] = Object.entries(hexInfoBuckets).find(([_, infos]) => {
+ return infos.some((info) => info?.asset.toBase58() === hotspot.id)
+ }) || [DEFAULT_HEX]
+
+ setActiveHex(hex)
+ if (hex !== DEFAULT_HEX) {
+ setActiveHotspotIndex(
+ hexInfoBuckets[hex].findIndex(
+ (info) => info.asset.toBase58() === hotspot.id,
+ ),
+ )
+ }
+ }
+ }
+ }, [anchorProvider, onEndReached, loadingInfos, hotspot])
+
+ // - show bottom sheet when activeHex is set
+ useEffect(() => {
+ if (activeHex || legendVisible) {
+ bottomSheetRef.current?.present()
+ } else {
+ bottomSheetRef.current?.dismiss()
+ }
+ }, [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],
+ // )
+
+ const activeHexItem = useMemo(() => {
+ if (!loadingInfos && activeHex) {
+ if (activeHex === DEFAULT_HEX && hotspot) {
+ return {
+ hotspot,
+ info: undefined,
+ }
+ }
+
+ const info = (hexInfoBuckets[activeHex] || [])[activeHotspotIndex]
+ if (info) {
+ return {
+ hotspot: hotspots.find(
+ (h) => h.id === info.asset.toBase58(),
+ ) as HotspotWithPendingRewards,
+ info,
+ }
+ }
+ }
+ }, [
+ loadingInfos,
+ hexInfoBuckets,
+ activeHex,
+ activeHotspotIndex,
+ hotspots,
+ hotspot,
+ ])
+
+ const isLoading = useMemo(
+ () => loading || !onEndReached || loadingInfos,
+ [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 handleLegendPress = useCallback(() => {
+ setLegendVisible(true)
+ }, [setLegendVisible])
+
+ const handleToggleNetwork = useCallback(() => {
+ setNetworkType(networkType === 'IOT' ? 'MOBILE' : 'IOT')
+ 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],
+ // )
+
+ return (
+
+
+
+
+
+
+
+ {/* */}
+
+ navigation.goBack()}
+ >
+
+
+ {t('collectablesScreen.hotspots.map.back')}
+
+
+
+
+
+
+
+
+ {t('collectablesScreen.hotspots.map.type', {
+ type: networkType,
+ })}
+
+
+
+
+
+
+
+
+
+
+ setActiveHex(undefined)}
+ onChange={(idx) => setBottomSheetSnapIndex(idx)}
+ >
+
+
+ {legendVisible && }
+ {activeHexItem && (
+
+ )}
+
+
+
+
+
+ )
+}
+
+export default HotspotMapScreen
diff --git a/src/features/hotspots/HotspotPage.tsx b/src/features/hotspots/HotspotPage.tsx
new file mode 100644
index 000000000..b8d4bbe9f
--- /dev/null
+++ b/src/features/hotspots/HotspotPage.tsx
@@ -0,0 +1,349 @@
+import Box from '@components/Box'
+import ScrollBox from '@components/ScrollBox'
+import Text from '@components/Text'
+import TouchableContainer from '@components/TouchableContainer'
+import useHotspots from '@hooks/useHotspots'
+import { useIsFocused, useNavigation, useRoute } from '@react-navigation/native'
+import { useColors, useSpacing } from '@config/theme/themeHooks'
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RefreshControl } from 'react-native'
+import { FlatList } from 'react-native-gesture-handler'
+import SegmentedControl from '@components/SegmentedControl'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { Search } from '@components/Search'
+import { Location, MarkerView } from '@rnmapbox/maps'
+import ImageBox from '@components/ImageBox'
+import CarotRight from '@assets/svgs/carot-right.svg'
+import { getDistance } from 'geolib'
+import { MOBILE_MINT, toNumber as heliumToNumber } from '@helium/spl-utils'
+import { BN } from '@coral-xyz/anchor'
+import { toNumber } from 'lodash'
+import MiniMap from '@components/MiniMap'
+import { HotspotNavigationProp } from '@services/HotspotService/pages/HotspotPage'
+import { HotspotWithPendingRewards } from '../../types/solana'
+import EmptyState from './EmptyState'
+
+const HotspotPage = () => {
+ 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 80%
rename from src/features/collectables/SettingUpAntennaScreen.tsx
rename to src/features/hotspots/SettingUpAntennaScreen.tsx
index 7672744fa..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'
@@ -53,13 +53,13 @@ const SettingUpAntennaScreen = () => {
{
entering={FadeIn}
exiting={FadeOut}
>
-
+
{t('antennaSetupScreen.settingUpComplete')}
@@ -100,17 +100,17 @@ const SettingUpAntennaScreen = () => {
exiting={FadeOut}
>
{t('collectablesScreen.rewardsError')}
@@ -129,24 +129,24 @@ const SettingUpAntennaScreen = () => {
exiting={FadeOut}
>
{t('antennaSetupScreen.settingUp')}
{t('antennaSetupScreen.settingUpBody')}
-
-
+
+
)}
@@ -157,20 +157,20 @@ const SettingUpAntennaScreen = () => {
style={{ marginBottom: bottom }}
>
+
}
/>
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 b0b620a32..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 = {
@@ -43,11 +43,11 @@ const CameraPermissionBottomSheetAlert = forwardRef(
}))
const bottomSheetModalRef = useRef(null)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const { m } = useSpacing()
+ const { backgroundStyle } = useOpacity('primaryBackground', 1)
+ const spacing = useSpacing()
const { colors } = useTheme()
const snapPoints = useMemo(() => ['40%'], [])
- const sheetHandleStyle = useMemo(() => ({ padding: m }), [m])
+ const sheetHandleStyle = useMemo(() => ({ padding: spacing.xl }), [spacing])
const { handleDismiss } = useBackHandler(bottomSheetModalRef)
const handleIndicatorStyle = useMemo(() => {
return {
@@ -95,29 +95,30 @@ const WarningContent = () => {
-
+
{t('keystone.connectKeystoneStart.warning') as string}
)
@@ -139,7 +140,7 @@ const ConnectKeystoneStart = () => {
@@ -147,10 +148,15 @@ const ConnectKeystoneStart = () => {
-
+
{t('keystone.connectKeystoneStart.title') as string}
-
+
{t('keystone.connectKeystoneStart.subtitle') as string}
@@ -161,17 +167,13 @@ const ConnectKeystoneStart = () => {
)
diff --git a/src/features/keystone/KeystoneAccountAssignScreen.tsx b/src/features/keystone/KeystoneAccountAssignScreen.tsx
index bca13beab..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'
@@ -82,7 +82,7 @@ const KeystoneAccountAssignScreen = () => {
if (hasAccounts) {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -105,31 +105,34 @@ const KeystoneAccountAssignScreen = () => {
{t('accountAssign.title')}
{
)
}
/>
-
+
+
+
{
style={{ height: 20, width: 20 }}
tintColors={{
true: colors.primaryText,
- false: colors.transparent10,
+ false: colors.secondaryText,
}}
- onCheckColor={colors.secondary}
+ onCheckColor={colors.primaryBackground}
onTintColor={colors.primaryText}
- tintColor={colors.transparent10}
+ tintColor={colors.secondaryText}
onFillColor={colors.primaryText}
onAnimationType="fill"
offAnimationType="fill"
@@ -182,9 +188,9 @@ const KeystoneAccountAssignScreen = () => {
/>
{t('accountAssign.setDefault')}
@@ -192,20 +198,20 @@ const KeystoneAccountAssignScreen = () => {
{!loading && existingNames?.has(alias) ? (
-
+
{t('accountAssign.nameExists')}
) : null}
{loading ? (
-
+
) : (
)}
diff --git a/src/features/keystone/KeystoneModal.tsx b/src/features/keystone/KeystoneModal.tsx
index a1beed44f..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'
@@ -43,7 +43,7 @@ const KeystoneModal = forwardRef(
useImperativeHandle(ref, () => ({ showKeystoneModal }))
const eventEmitter = useMemo(() => new EventEmitter(), [])
const { currentAccount } = useAccountStorage()
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
+ const { backgroundStyle } = useOpacity('primaryBackground', 1)
const bottomSheetModalRef = useRef(null)
const [solSignRequest, setSolSignRequest] =
useState()
@@ -114,9 +114,9 @@ const KeystoneModal = forwardRef(
[],
)
const snapPoints = useMemo(() => ['100%'], [])
- const { m } = useSpacing()
+ const { xl } = useSpacing()
const { colors } = useTheme()
- const sheetHandleStyle = useMemo(() => ({ padding: m }), [m])
+ const sheetHandleStyle = useMemo(() => ({ padding: xl }), [xl])
const { handleDismiss } = useBackHandler(bottomSheetModalRef)
const handleIndicatorStyle = useMemo(() => {
@@ -125,7 +125,7 @@ const KeystoneModal = forwardRef(
}
}, [colors.secondaryText])
return (
-
+
{
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isScanQrCodeComplete])
return (
-
+
{
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)),
@@ -73,26 +68,18 @@ const SelectKeystoneAccountsScreen = () => {
const onNext = useCallback(() => {
storageSelectedAccounts()
- if (hasAccounts) {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- navigation.replace('TabBarNavigator', {
- screen: 'Home',
- params: {
- screen: 'KeystoneAccountAssignScreen',
- },
- })
- } else {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- navigation.replace('OnboardingNavigator', {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ navigation.replace('ServiceSheetNavigator', {
+ screen: 'AccountsService',
+ params: {
screen: 'KeystoneNavigator',
params: {
screen: 'KeystoneAccountAssignScreen',
},
- })
- }
- }, [hasAccounts, navigation, selected])
+ },
+ })
+ }, [navigation, selected])
const fetchBalance = async (publicKey: string) => {
if (connection) {
@@ -137,22 +124,22 @@ const SelectKeystoneAccountsScreen = () => {
flexDirection="row"
minHeight={72}
alignItems="center"
- paddingHorizontal="m"
- paddingVertical="m"
+ paddingHorizontal="4"
+ paddingVertical="4"
borderBottomColor="primaryBackground"
borderBottomWidth={index === derivationAccounts.length - 1 ? 0 : 1}
>
-
+
{item.path}
@@ -161,7 +148,7 @@ const SelectKeystoneAccountsScreen = () => {
)}
@@ -178,11 +165,11 @@ const SelectKeystoneAccountsScreen = () => {
style={{ height: 18, width: 18 }}
tintColors={{
true: colors.primaryText,
- false: colors.transparent10,
+ false: colors.secondaryText,
}}
- onCheckColor={colors.secondary}
+ onCheckColor={colors.primaryBackground}
onTintColor={colors.primaryText}
- tintColor={colors.transparent10}
+ tintColor={colors.secondaryText}
onFillColor={colors.primaryText}
onAnimationType="fill"
offAnimationType="fill"
@@ -193,28 +180,29 @@ const SelectKeystoneAccountsScreen = () => {
)
},
- [
- colors.primaryText,
- colors.secondary,
- colors.transparent10,
- derivationAccounts,
- selected,
- ],
+ [colors, derivationAccounts, selected],
)
return (
{t('keystone.selectKeystoneAccounts.title')}
-
+
{t('keystone.selectKeystoneAccounts.subtitle')}
{
/>
diff --git a/src/features/keystone/SignTx/SignTxModal.tsx b/src/features/keystone/SignTx/SignTxModal.tsx
index 6abd97d9d..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'
@@ -83,9 +83,9 @@ const DaynamicQrScanner = ({ onBarCodeScanned, progress }: Props) => {
bottom="15%"
width="95%"
alignSelf="center"
- paddingHorizontal="s"
+ paddingHorizontal="1"
>
-
+
{t('keystone.payment.scanTxQrcodeScreenSubtitle3')}
@@ -134,7 +134,7 @@ const ScanTxQrcodeScreen = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [signature, progress])
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('4')
return (
{openQrCodeScanner && (
@@ -146,22 +146,22 @@ const ScanTxQrcodeScreen = ({
-
+
{openQrCodeScanner && (
-
+
{t('keystone.scanQrCode')}
)}
{
eventEmitter.emit('closeKeystoneSignatureModal', '')
}}
@@ -172,16 +172,20 @@ const ScanTxQrcodeScreen = ({
flex={1}
alignItems="center"
justifyContent="space-between"
- padding="l"
+ padding="4"
marginTop="xl"
>
-
+
-
+
{t('keystone.payment.scanTxQrcodeScreenTitle')}
-
+
{t('keystone.payment.scanTxQrcodeScreenSubtitle1')}
{/* show the sol sign request qrcode */}
@@ -191,24 +195,20 @@ const ScanTxQrcodeScreen = ({
cborData={solSignRequestUr.cbor.toString('hex')}
/>
)}
-
+
{t('keystone.payment.scanTxQrcodeScreenSubtitle2')}
)}
diff --git a/src/features/ledger/DeviceChooseType.tsx b/src/features/ledger/DeviceChooseType.tsx
index 286c839db..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'
@@ -32,50 +32,55 @@ const DeviceChooseType = () => {
-
+
{t('ledger.chooseType.title')}
-
+
{t('ledger.chooseType.bluetooth.title')}
-
+
{t('ledger.chooseType.bluetooth.types')}
-
+
{t('ledger.chooseType.usb.title')}
-
+
{t('ledger.chooseType.usb.types')}
diff --git a/src/features/ledger/DeviceScan.tsx b/src/features/ledger/DeviceScan.tsx
index a7f4c96b7..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'
@@ -32,7 +32,7 @@ const DeviceScan = () => {
const route = useRoute()
const { primaryText } = useColors()
- const { backgroundStyle } = useOpacity('secondary', 1)
+ const { backgroundStyle } = useOpacity('bg.tertiary', 1)
const bottomSheetModalRef = useRef(null)
const [contentHeight, setContentHeight] = useState(0)
const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
@@ -108,21 +108,21 @@ const DeviceScan = () => {
return (
-
+
{device.name}
@@ -135,29 +135,30 @@ const DeviceScan = () => {
return (
-
+
{t('ledger.scan.title')}
{
{t('ledger.scan.subtitle')}
-
+
{
return (
-
+
{device.name}
@@ -85,27 +85,27 @@ const DeviceScanUsb = () => {
return (
{t('ledger.scan.title')}
{
{t('ledger.scan.subtitleUsb')}
-
+
@@ -33,7 +33,7 @@ type SectionData = {
}
}
const DeviceShow = () => {
- const homeNav = useNavigation()
+ const homeNav = useNavigation()
const navigation = useNavigation()
const route = useRoute()
const { ledgerDevice } = route.params
@@ -145,46 +145,46 @@ const DeviceShow = () => {
return (
<>
-
-
+
+
-
+
{t('ledger.show.title')}
{t('ledger.show.subtitle')}
{t('accountImport.accountLimitLedger')}
{isScanning && (
-
+
)}
@@ -203,20 +203,20 @@ const DeviceShow = () => {
{index === 0 && PageHeader()}
-
+
{title}
{index === 0 && (
-
+
{selectAll
? t('ledger.show.deselectAll')
: t('ledger.show.selectAll')}
@@ -236,9 +236,9 @@ const DeviceShow = () => {
{index === 0 && newLedgerAccounts?.length === 0 && (
{t('ledger.show.emptyAccount', {
@@ -296,7 +296,7 @@ const DeviceShow = () => {
}, [accountsToAdd, ledgerDevice, navigation, upsertAccounts])
const handleClose = useCallback(() => {
- homeNav.navigate('AccountsScreen')
+ homeNav.navigate('TokensTabs')
}, [homeNav])
const onCheckboxToggled = useCallback(
@@ -347,24 +347,24 @@ const DeviceShow = () => {
bottom={0}
left={0}
right={0}
- borderTopColor="secondaryIcon"
+ borderTopColor="secondaryText"
borderTopWidth={1}
height="11%"
>
diff --git a/src/features/ledger/LedgerAccountListItem.tsx b/src/features/ledger/LedgerAccountListItem.tsx
index 9efa0ccf4..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'
@@ -68,25 +68,25 @@ const LedgerAccountListItem = ({
)
return (
-
+
-
-
+
+
{account.alias}
-
+
- {hasBottomBorder ? : null}
+ {hasBottomBorder ? (
+
+ ) : null}
)
}
diff --git a/src/features/ledger/LedgerConnectSteps.tsx b/src/features/ledger/LedgerConnectSteps.tsx
index 97aa35342..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 = {
@@ -20,39 +20,43 @@ const LedgerConnectSteps = ({ onLayout, onRetry }: Props) => {
const { primaryText } = useColors()
return (
-
-
+
+
-
+
{t('ledger.connectError.title')}
-
+
{t('ledger.connectError.subtitle')}
{steps.map((step) => (
-
+
{step}
))}
-
+
{t('generic.tryAgain')}
diff --git a/src/features/ledger/LedgerModal.tsx b/src/features/ledger/LedgerModal.tsx
index 651265b56..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'
@@ -54,9 +53,9 @@ const LedgerModal = forwardRef(
const { currentAccount } = useAccountStorage()
const bottomSheetModalRef = useRef(null)
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
+ const { backgroundStyle } = useOpacity('bg.tertiary', 1)
const { setIsShowing } = useBackHandler(bottomSheetModalRef)
- const { secondaryText } = useColors()
+ const { primaryText } = useColors()
const { t } = useTranslation()
const { getTransport, openSolanaApp } = useLedger()
const [transactionBuffer, setTransactionBuffer] = useState()
@@ -71,8 +70,6 @@ const LedgerModal = forwardRef(
| 'enableBlindSign'
>('loading')
- const animatedContentHeight = useSharedValue(0)
-
const openAppAndSign = useCallback(
async ({
transactionBuffer: tBuffer,
@@ -216,9 +213,9 @@ const LedgerModal = forwardRef(
const handleIndicatorStyle = useMemo(() => {
return {
- backgroundColor: secondaryText,
+ backgroundColor: primaryText,
}
- }, [secondaryText])
+ }, [primaryText])
const deviceModelId = useMemo(() => {
let model = DeviceModelId.nanoX
@@ -271,7 +268,7 @@ const LedgerModal = forwardRef(
return null
case 'openApp':
return (
-
+
{t('ledger.openTheSolanaApp', {
device: currentAccount?.ledgerDevice?.name,
})}
@@ -279,7 +276,7 @@ const LedgerModal = forwardRef(
)
case 'sign':
return (
-
+
{t('ledger.pleaseConfirmTransaction', {
device: currentAccount?.ledgerDevice?.name,
})}
@@ -288,19 +285,19 @@ const LedgerModal = forwardRef(
case 'enterPinCode':
return (
-
+
{t('ledger.pleaseEnterPinCode', {
device: currentAccount?.ledgerDevice?.name,
})}
-
+
{t('generic.tryAgain')}
@@ -309,17 +306,17 @@ const LedgerModal = forwardRef(
case 'enableBlindSign':
return (
-
+
{t('ledger.enableBlindSign')}
-
+
{t('generic.tryAgain')}
@@ -335,19 +332,16 @@ const LedgerModal = forwardRef(
return (
- {/* */}
-
+
diff --git a/src/features/ledger/PairStart.tsx b/src/features/ledger/PairStart.tsx
index 393063eb4..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 = () => {
@@ -24,44 +24,49 @@ const PairStart = () => {
-
+
{t('ledger.pairStart.title')}
-
+
{t('ledger.pairStart.subtitle')}
{t('accountImport.accountLimit')}
)
diff --git a/src/features/ledger/PairSuccess.tsx b/src/features/ledger/PairSuccess.tsx
index 80be4e92d..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()
@@ -23,7 +23,7 @@ const PairSuccess = () => {
index: 0,
routes: [
{
- name: 'TabBarNavigator',
+ name: 'ServiceSheetNavigator',
},
],
})
@@ -36,28 +36,28 @@ const PairSuccess = () => {
-
+
{t('ledger.success.title')}
-
+
{t('ledger.success.subtitle')}
)
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 f2bc551d4..8ae0284f5 100644
--- a/src/features/lock/LockScreen.tsx
+++ b/src/features/lock/LockScreen.tsx
@@ -8,13 +8,15 @@ import { useAsync } from 'react-async-hook'
import { useTranslation } from 'react-i18next'
import useAppState from 'react-native-appstate-hook'
import { FadeIn, FadeOutDown } from 'react-native-reanimated'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { ThemeProvider } from '@shopify/restyle'
+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) => {
@@ -125,4 +127,12 @@ const LockScreen = ({ children }: Props) => {
)
}
-export default memo(LockScreen)
+const LockScreenWrapper = ({ children }: Props) => {
+ return (
+
+ {children}
+
+ )
+}
+
+export default memo(LockScreenWrapper)
diff --git a/src/features/migration/SolanaMigration.tsx b/src/features/migration/SolanaMigration.tsx
index df7c95944..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,
@@ -155,7 +155,7 @@ const SolanaMigration = ({
const boxProps = {
backgroundColor: 'transparent',
flex: 1,
- padding: 'm',
+ padding: '4',
alignItems: 'center',
justifyContent: 'center',
} as BoxProps
@@ -176,7 +176,7 @@ const SolanaMigration = ({
{t('solanaMigrationScreen.migrationComplete')}
{t('solanaMigrationScreen.error')}
@@ -245,9 +245,9 @@ const SolanaMigration = ({
exiting={FadeOut}
>
{t('solanaMigrationScreen.migratingBody')}
-
-
+
+
{total > 200 && (
{progress} / {total}
@@ -286,8 +286,8 @@ const SolanaMigration = ({
{(error || migrationError) && (
0 && (
)}
diff --git a/src/features/modals/InsufficientSolConversionModal.tsx b/src/features/modals/InsufficientSolConversionModal.tsx
index 4e9ddd44b..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()
@@ -168,24 +168,29 @@ const InsufficientSolConversionModal: FC = () => {
zIndex={9999}
height="100%"
width="100%"
- paddingBottom="xl"
+ paddingBottom="8"
>
-
+
{t('insufficientSolConversionModal.title')}
-
+
@@ -194,7 +199,7 @@ const InsufficientSolConversionModal: FC = () => {
{validInputMints.map((mint) => (
{
/>
))}
-
- {loading && }
+
+ {loading && }
{!loading && !hasAtLeastOne && (
-
-
+
+
{t('insufficientSolConversionModal.noBalance')}
)}
{!loading && hasAtLeastOne && (
<>
-
+
{t('swapsScreen.youPay')}
-
+
{inputAmount}
-
+
{symbol}
-
+
{t('swapsScreen.youReceive')}
-
+
~0.02
-
+
SOL
{showError}
@@ -276,19 +285,19 @@ const InsufficientSolConversionModal: FC = () => {
setUseAuto((ua) => !ua)}
/>
-
+
{t('insufficientSolConversionModal.useAuto')}
@@ -296,16 +305,16 @@ const InsufficientSolConversionModal: FC = () => {
{!loading && (
{
{hasAtLeastOne && (
+
) : undefined
}
/>
diff --git a/src/features/notifications/AccountSlider.tsx b/src/features/notifications/AccountSlider.tsx
index 5c3a7f476..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'
@@ -108,7 +108,7 @@ const AccountSlider = () => {
const keyExtractor = useCallback((item) => item || '', [])
return (
-
+
@@ -64,8 +64,8 @@ const AccountSliderIcon = ({
width={15}
borderWidth={2}
borderColor="primaryBackground"
- borderRadius="round"
- backgroundColor="malachite"
+ borderRadius="full"
+ backgroundColor="green.500"
/>
>
)
diff --git a/src/features/notifications/NotificationDetailBanner.tsx b/src/features/notifications/NotificationDetailBanner.tsx
index 7707f0c70..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 }) => {
@@ -34,7 +34,7 @@ const NotificationDetailBanner = ({ icon }: { icon: string }) => {
)
diff --git a/src/features/notifications/NotificationDetails.tsx b/src/features/notifications/NotificationDetails.tsx
index 26b3a9456..1b715bd8e 100644
--- a/src/features/notifications/NotificationDetails.tsx
+++ b/src/features/notifications/NotificationDetails.tsx
@@ -2,21 +2,20 @@ import React, { memo, useEffect, useMemo } from 'react'
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
import { formatDistanceToNow, parseISO } from 'date-fns'
import Animated from 'react-native-reanimated'
-import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import Box from '@components/Box'
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
@@ -67,42 +66,46 @@ const NotificationDetails = () => {
return (
-
-
+
{notification.title}
-
+
{time}
{parseMarkup(notification.body)}
-
+
)
}
diff --git a/src/features/notifications/NotificationListItem.tsx b/src/features/notifications/NotificationListItem.tsx
index 31a7a2134..7c0ec886b 100644
--- a/src/features/notifications/NotificationListItem.tsx
+++ b/src/features/notifications/NotificationListItem.tsx
@@ -40,24 +40,24 @@ const NotificationListItem = ({
-
+
{!viewed && (
)}
-
+
{subtitle}
{time}
diff --git a/src/features/notifications/NotificationsList.tsx b/src/features/notifications/NotificationsList.tsx
index 0e0b3767c..c39506083 100644
--- a/src/features/notifications/NotificationsList.tsx
+++ b/src/features/notifications/NotificationsList.tsx
@@ -4,11 +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'
@@ -29,9 +30,9 @@ const NotificationsList = ({
const contentContainer = useMemo(
() => ({
- paddingBottom: spacing.xxxl,
+ paddingBottom: spacing['15'],
}),
- [spacing.xxxl],
+ [spacing],
)
const SectionData = useMemo((): {
@@ -79,7 +80,7 @@ const NotificationsList = ({
return (
(
-
+
{t('notifications.emptyTitle')}
@@ -114,13 +115,17 @@ const NotificationsList = ({
-
+
{sectionTitle}
@@ -132,7 +137,7 @@ const NotificationsList = ({
const keyExtractor = useCallback((item, index) => item.time + index, [])
return (
-
+
{HeaderComponent}
-
+
)
}
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 3639379d0..2273a3dd3 100644
--- a/src/features/notifications/NotificationsScreen.tsx
+++ b/src/features/notifications/NotificationsScreen.tsx
@@ -1,21 +1,15 @@
import React, { memo, useCallback, useEffect, useMemo } from 'react'
import { useIsFocused } from '@react-navigation/native'
import { Linking } from 'react-native'
-import { useTranslation } from 'react-i18next'
-import { Edge } from 'react-native-safe-area-context'
-import Text from '@components/Text'
-import SafeAreaBox from '@components/SafeAreaBox'
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 = () => {
- const { t } = useTranslation()
- const safeEdges = useMemo(() => ['top'] as Edge[], [])
const { selectedNotification, updateAllNotifications } =
useNotificationStorage()
const isFocused = useIsFocused()
@@ -33,14 +27,11 @@ const NotificationsScreen = () => {
const HeaderComponent = useMemo(() => {
return (
- <>
-
- {t('notifications.title')}
-
+
- >
+
)
- }, [t])
+ }, [])
const FooterComponent = useMemo(() => {
return selectedNotification?.actionTitle &&
@@ -49,17 +40,17 @@ const NotificationsScreen = () => {
position="absolute"
bottom={0}
width="100%"
- paddingHorizontal="m"
- marginBottom="xl"
+ paddingHorizontal="4"
+ marginBottom="8"
>
) : (
@@ -69,16 +60,12 @@ const NotificationsScreen = () => {
return (
-
+
-
+
)
}
diff --git a/src/features/onboarding/AccountAssignScreen.tsx b/src/features/onboarding/AccountAssignScreen.tsx
index c2793c824..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,15 +24,15 @@ 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 { RootNavigationProp } from '../../navigation/rootTypes'
-import { useSolana } from '../../solana/SolanaProvider'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { HomeStackParamList } from '../home/homeTypes'
+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'
-type Route = RouteProp
+type Route = RouteProp
const AccountAssignScreen = () => {
const route = useRoute()
@@ -147,7 +150,7 @@ const AccountAssignScreen = () => {
if (hasAccounts) {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
reset()
} else {
@@ -174,57 +177,63 @@ const AccountAssignScreen = () => {
{t('accountAssign.title')}
-
+
+
+
{
style={{ height: 20, width: 20 }}
tintColors={{
true: colors.primaryText,
- false: colors.transparent10,
+ false: colors.secondaryText,
}}
- onCheckColor={colors.secondary}
+ onCheckColor={colors.primaryBackground}
onTintColor={colors.primaryText}
- tintColor={colors.transparent10}
+ tintColor={colors.secondaryText}
onFillColor={colors.primaryText}
onAnimationType="fill"
offAnimationType="fill"
@@ -246,9 +255,9 @@ const AccountAssignScreen = () => {
/>
{t('accountAssign.setDefault')}
@@ -256,20 +265,20 @@ const AccountAssignScreen = () => {
{!loading && existingNames?.has(alias) ? (
-
+
{t('accountAssign.nameExists')}
) : null}
{loading ? (
-
+
) : (
)}
diff --git a/src/features/onboarding/AccountConfirmPinScreen.tsx b/src/features/onboarding/AccountConfirmPinScreen.tsx
index dfad03c90..9710f2579 100644
--- a/src/features/onboarding/AccountConfirmPinScreen.tsx
+++ b/src/features/onboarding/AccountConfirmPinScreen.tsx
@@ -2,12 +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 { RootNavigationProp } from '../../navigation/rootTypes'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { ThemeProvider } from '@shopify/restyle'
+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'
@@ -56,7 +58,7 @@ const AccountConfirmPinScreen = () => {
index: 0,
routes: [
{
- name: 'TabBarNavigator',
+ name: 'ServiceSheetNavigator',
},
],
})
@@ -86,4 +88,12 @@ const AccountConfirmPinScreen = () => {
)
}
-export default AccountConfirmPinScreen
+const AccountConfirmPinScreenWrapper = () => {
+ return (
+
+
+
+ )
+}
+
+export default AccountConfirmPinScreenWrapper
diff --git a/src/features/onboarding/AccountCreatePinScreen.tsx b/src/features/onboarding/AccountCreatePinScreen.tsx
index bd6fc887f..75c218902 100644
--- a/src/features/onboarding/AccountCreatePinScreen.tsx
+++ b/src/features/onboarding/AccountCreatePinScreen.tsx
@@ -6,6 +6,8 @@ import PinDisplay from '@components/PinDisplay'
import Keypad from '@components/Keypad'
import Box from '@components/Box'
import { KeypadInput } from '@components/KeypadButton'
+import { ThemeProvider } from '@shopify/restyle'
+import { darkTheme } from '@config/theme/theme'
import {
CreateAccountNavigationProp,
CreateAccountStackParamList,
@@ -59,14 +61,15 @@ const AccountCreatePinScreen = () => {
{
{t('accountSetup.createPin.title')}
-
+
{t('accountSetup.createPin.subtitle')}
-
+
)
}
-export default AccountCreatePinScreen
+const AccountCreatePinScreenWrapper = () => {
+ return (
+
+
+
+ )
+}
+
+export default AccountCreatePinScreenWrapper
diff --git a/src/features/onboarding/CreateImportAccountScreen.tsx b/src/features/onboarding/CreateImportAccountScreen.tsx
index 26d3d5b96..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'
@@ -39,41 +39,63 @@ const CreateImportAccountScreen = () => {
}, [navigation])
return (
-
-
- {t('accountSetup.createImport.title')}
-
-
-
+
+
+
+ {t('accountSetup.createImport.title')}
+
+
+
+
-
+
{t('accountSetup.createImport.import')}
-
+
-
+
-
+
{t('accountSetup.createImport.create')}
-
+
-
+
-
+
{t('accountSetup.createImport.keystone')}
-
+
-
+
{t('accountSetup.createImport.ledger')}
@@ -83,8 +105,8 @@ const CreateImportAccountScreen = () => {
const NetTypeSegment = (boxProps: Props) => {
const { t } = useTranslation()
const { xs: switchMarginHorizontal } = useSpacing()
const colors = useColors()
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
const { onboardingData, setOnboardingData } = useOnboarding()
const { enableTestnet } = useAppStorage()
const trackColor = useMemo(
- () => ({ false: colors.secondaryText, true: colors.blueBright500 }),
+ () => ({ false: colors.secondaryText, true: colors['blue.light-500'] }),
[colors],
)
@@ -68,10 +68,10 @@ const NetTypeSegment = (boxProps: Props) => {
{
{
[],
)
return (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
)
}
export default memo(OnboardingNavigator)
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 834833f92..fd379fabb 100644
--- a/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx
+++ b/src/features/onboarding/cli-import/CLIAccountImportStartScreen.tsx
@@ -2,13 +2,14 @@ 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'
import Box from '@components/Box'
import CloseButton from '@components/CloseButton'
import TextTransform from '@components/TextTransform'
+import BackScreen from '@components/BackScreen'
import { CLIAccountNavigationProp } from './CLIAccountNavigatorTypes'
const CLIAccountImportStartScreen = () => {
@@ -25,41 +26,54 @@ const CLIAccountImportStartScreen = () => {
}, [navigation])
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
- {t('accountImport.cli.import.title')}
-
+
+ {t('accountImport.cli.import.title')}
+
-
-
+
+
-
-
+
+
+
-
-
+
+
)
}
diff --git a/src/features/onboarding/cli-import/CLIAccountNavigator.tsx b/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
index df488f262..525f78c8a 100644
--- a/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
+++ b/src/features/onboarding/cli-import/CLIAccountNavigator.tsx
@@ -1,5 +1,6 @@
import * as React from 'react'
import { createStackNavigator } from '@react-navigation/stack'
+import { useColors } from '@config/theme/themeHooks'
import CLIAccountImportStartScreen from './CLIAccountImportStartScreen'
import CLIPasswordScreen from './CLIPasswordScreen'
import CLIQrScanner from './CLIQrScanner'
@@ -8,9 +9,18 @@ import AccountAssignScreen from '../AccountAssignScreen'
const CLIAccountStack = createStackNavigator()
const CLIAccountNavigator = () => {
+ const colors = useColors()
+
return (
<>
-
+
{
const [password, setPassword] = useState('')
const inputStyle = useMemo(() => {
- return { color: 'white', fontSize: 24, textAlign: 'center' } as TextStyle
+ return {
+ color: 'base.white',
+ fontSize: 24,
+ textAlign: 'center',
+ } as TextStyle
}, [])
const handleNext = useCallback(async () => {
@@ -98,21 +102,26 @@ const CLIPasswordScreen = () => {
])
return (
-
-
+
+
-
+
{t('accountImport.cli.password.title')}
{t('accountImport.cli.password.body')}
@@ -122,7 +131,7 @@ const CLIPasswordScreen = () => {
variant="transparent"
textInputProps={{
onChangeText: setPassword,
- placeholderTextColor: 'grey500',
+ placeholderTextColor: 'gray.500',
value: password,
placeholder: 'password',
autoCorrect: false,
@@ -131,19 +140,19 @@ const CLIPasswordScreen = () => {
style: inputStyle,
secureTextEntry: true,
}}
- marginTop="xl"
+ marginTop="8"
width="100%"
/>
diff --git a/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx b/src/features/onboarding/create/AccountCreatePassphraseScreen.tsx
index be85375c7..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'
@@ -62,33 +65,39 @@ const AccountCreatePassphraseScreen = () => {
return (
<>
-
+
-
+
{t('accountSetup.passphrase.title')}
{t('accountSetup.passphrase.subtitle1')}
{t('accountSetup.passphrase.subtitle2')}
diff --git a/src/features/onboarding/create/AccountCreateStart.tsx b/src/features/onboarding/create/AccountCreateStart.tsx
index c7ec5a954..62f90355b 100644
--- a/src/features/onboarding/create/AccountCreateStart.tsx
+++ b/src/features/onboarding/create/AccountCreateStart.tsx
@@ -1,13 +1,14 @@
import React, { memo, useCallback } from 'react'
+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 }
@@ -15,6 +16,7 @@ const AccountCreateStart = ({ onCreate, inline }: Props) => {
const { t } = useTranslation()
const { reachedAccountLimit } = useAccountStorage()
const navigation = useNavigation()
+ const colors = useColors()
const onClose = useCallback(() => {
navigation.goBack()
@@ -23,35 +25,36 @@ const AccountCreateStart = ({ onCreate, inline }: Props) => {
return (
-
+
{t('accountSetup.title')}
{t('accountSetup.subtitle1')}
{t('accountSetup.subtitle2')}
@@ -59,26 +62,26 @@ const AccountCreateStart = ({ onCreate, inline }: Props) => {
{t('accountImport.accountLimit')}
diff --git a/src/features/onboarding/create/AccountEnterPassphraseScreen.tsx b/src/features/onboarding/create/AccountEnterPassphraseScreen.tsx
index f6b14e997..b0b4dea86 100644
--- a/src/features/onboarding/create/AccountEnterPassphraseScreen.tsx
+++ b/src/features/onboarding/create/AccountEnterPassphraseScreen.tsx
@@ -18,10 +18,9 @@ const AccountEnterPassphraseScreen = () => {
onboardingData: { words },
} = useOnboarding()
- const onWordsConfirmed = useCallback(
- () => navigation.navigate('AccountAssignScreen', params),
- [navigation, params],
- )
+ const onWordsConfirmed = useCallback(() => {
+ navigation.navigate('AccountAssignScreen', params)
+ }, [navigation, params])
return (
diff --git a/src/features/onboarding/create/ConfirmWordsScreen.tsx b/src/features/onboarding/create/ConfirmWordsScreen.tsx
index c63f38169..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'
@@ -15,18 +15,18 @@ import { CreateAccountNavigationProp } from './createAccountNavTypes'
import PassphraseAutocomplete from '../import/PassphraseAutocomplete'
const accentColors = [
- 'purple500',
- 'blueBright500',
- 'greenBright500',
- 'orange500',
- 'persianRose',
- 'grey350',
- 'flamenco',
- 'electricViolet',
- 'malachite',
- 'turquoise',
- 'white',
- 'red500',
+ 'purple.500',
+ 'blue.light-500',
+ 'green.light-500',
+ 'orange.500',
+ 'pink.500',
+ 'gray.500',
+ 'orange.500',
+ 'violet.200',
+ 'green.500',
+ 'cyan.500',
+ 'base.white',
+ 'error.500',
] as Color[]
type Props = {
@@ -49,7 +49,7 @@ const ConfirmWordsScreen: React.FC = ({
const navigation = useNavigation()
const flatlistRef = useRef(null)
const colors = useColors()
- const flatListStyle = usePaddingStyle('m', ['left', 'right'])
+ const flatListStyle = usePaddingStyle('4', ['left', 'right'])
const wordCount = mnemonic.length
const [words, setWords] = useState<(string | null)[]>(
new Array(wordCount).fill(null),
@@ -138,13 +138,13 @@ const ConfirmWordsScreen: React.FC = ({
({ index, item: w }: { item: string | null; index: number }) => {
return (
= ({
style={{ transform: [{ translateX: shakeAnim.current }] }}
>
{title || t('accountSetup.confirm.title')}
{t('accountSetup.confirm.subtitleOrdinal', {
ordinal: wordIndex + 1,
@@ -248,9 +249,9 @@ const ConfirmWordsScreen: React.FC = ({
/>
-
+
= ({
{__DEV__ && (
()
diff --git a/src/features/onboarding/create/PhraseChip.tsx b/src/features/onboarding/create/PhraseChip.tsx
index d522f5c19..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
@@ -26,22 +26,22 @@ const PhraseChip = ({
disabled,
...props
}: Props) => {
- const { surface, primary } = useColors()
+ const { cardBackground, primaryText } = useColors()
const [underlayShowing, setUnderlayShowing] = useState(false)
const getBackgroundColor = useCallback((): Color => {
- if (fail) return 'error'
- if (success) return 'greenBright500'
+ if (fail) return 'error.500'
+ if (success) return 'green.light-500'
return 'transparent10'
}, [fail, success])
const getIcon = useCallback(() => {
- if (success) return
+ if (success) return
- if (fail) return
+ if (fail) return
return null
- }, [fail, primary, success])
+ }, [fail, primaryText, success])
const handleUnderlayChange = useCallback(
(val: boolean) => () => setUnderlayShowing(val),
@@ -51,11 +51,11 @@ const PhraseChip = ({
return (
{upperCase(title)}
diff --git a/src/features/onboarding/import/AccountImportScreen.tsx b/src/features/onboarding/import/AccountImportScreen.tsx
index 618814063..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'
@@ -25,18 +25,18 @@ import {
} from './importAccountNavTypes'
const accentColors = [
- 'purple500',
- 'blueBright500',
- 'greenBright500',
- 'orange500',
- 'persianRose',
- 'grey350',
- 'flamenco',
- 'electricViolet',
- 'malachite',
- 'turquoise',
- 'white',
- 'red500',
+ 'purple.500',
+ 'blue.light-500',
+ 'green.light-500',
+ 'orange.500',
+ 'pink.500',
+ 'fuchsia.500',
+ 'orange.500',
+ 'violet.500',
+ 'green.500',
+ 'ros.500',
+ 'cyan.500',
+ 'error.500',
] as Color[]
type Route = RouteProp
@@ -52,7 +52,7 @@ const AccountImportScreen = () => {
const [wordCount, setWordCount] = useState(12)
const colors = useColors()
const { t } = useTranslation()
- const flatListStyle = usePaddingStyle('m', ['left', 'right'])
+ const flatListStyle = usePaddingStyle('4', ['left', 'right'])
const [wordIndex, setWordIndex] = useState(0)
const [words, setWords] = useState<(string | null)[]>(
@@ -260,13 +260,13 @@ const AccountImportScreen = () => {
({ index, item: w }: { item: string | null; index: number }) => {
return (
{
return (
-
+
{
keyboardShouldPersistTaps="always"
>
{t('accountImport.wordEntry.title', { totalWords: wordCount })}
@@ -338,7 +339,7 @@ const AccountImportScreen = () => {
flex={1}
alignItems="center"
>
-
+
{t('accountImport.wordEntry.changeWordAmount', {
totalWords: wordCount === 12 ? 24 : 12,
})}
diff --git a/src/features/onboarding/import/AccountImportStartScreen.tsx b/src/features/onboarding/import/AccountImportStartScreen.tsx
index 971d21109..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
@@ -79,59 +79,60 @@ const AccountImportStartScreen = ({ inline }: { inline?: boolean }) => {
flex={1}
flexDirection="column"
edges={edges}
- backgroundColor="secondaryBackground"
+ backgroundColor="primaryBackground"
>
{isInline ? null : (
-
+
)}
{t('accountImport.title')}
{reachedAccountLimit
? t('accountImport.accountLimit')
: t('accountImport.pickKeyType')}
-
+
{
/>
{
/>
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 5ef30754c..c831151a0 100644
--- a/src/features/onboarding/import/ImportPrivateKey.tsx
+++ b/src/features/onboarding/import/ImportPrivateKey.tsx
@@ -11,15 +11,15 @@ import { Keypair } from '@solana/web3.js'
import bs58 from 'bs58'
import { Buffer } from 'buffer'
import React, { memo, useCallback, useState } from 'react'
-import { useAsync } from 'react-async-hook'
+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'
@@ -65,8 +65,8 @@ const ImportPrivateKey = () => {
[accounts, setOnboardingData, t],
)
- const decodePrivateKey = useCallback(
- async (key?: string) => {
+ const { execute: decodePrivateKey, loading: decodingPrivateKey } =
+ useAsyncCallback(async (key?: string) => {
setPublicKey(undefined)
if (key) {
@@ -130,9 +130,7 @@ const ImportPrivateKey = () => {
Logger.error(e)
}
}
- },
- [createAccount, encodedKey, password, t],
- )
+ })
useAsync(async () => {
await decodePrivateKey()
@@ -142,7 +140,7 @@ const ImportPrivateKey = () => {
if (navigation.canGoBack()) {
navigation.goBack()
} else if (hasAccounts) {
- navigation.replace('TabBarNavigator')
+ navigation.replace('ServiceSheetNavigator')
} else {
navigation.replace('OnboardingNavigator')
}
@@ -152,11 +150,14 @@ const ImportPrivateKey = () => {
function getRoute(subRoute: string) {
if (hasAccounts) {
return [
- 'TabBarNavigator',
+ 'ServiceSheetNavigator',
{
- screen: 'Home',
+ screen: 'AccountsService',
params: {
- screen: subRoute,
+ screen: 'ReImportAccountNavigator',
+ params: {
+ screen: subRoute,
+ },
},
},
]
@@ -195,15 +196,16 @@ const ImportPrivateKey = () => {
)
return (
-
-
-
+
+
+
{t('accountImport.privateKey.title')}
{t('accountImport.privateKey.paste')}
@@ -222,10 +224,11 @@ const ImportPrivateKey = () => {
variant="underline"
/>
Enter the password you set for your private key.
@@ -240,24 +243,31 @@ const ImportPrivateKey = () => {
autoComplete: 'off',
returnKeyType: 'done',
}}
+ textColor="primaryText"
variant="underline"
/>
{error}
-
+
{t('accountImport.privateKey.body')}
@@ -267,13 +277,14 @@ const ImportPrivateKey = () => {
)
diff --git a/src/features/onboarding/import/ImportReplaceWordModal.tsx b/src/features/onboarding/import/ImportReplaceWordModal.tsx
index 726b2f187..35ef755a3 100644
--- a/src/features/onboarding/import/ImportReplaceWordModal.tsx
+++ b/src/features/onboarding/import/ImportReplaceWordModal.tsx
@@ -1,13 +1,14 @@
import React, { useCallback, useEffect, useState } from 'react'
-import { Modal, ScrollView } from 'react-native'
+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'
type Props = {
@@ -69,12 +70,12 @@ const ImportReplaceWordModal = ({
opacity={0.97}
/>
-
+
-
+
-
))}
-
+
diff --git a/src/features/onboarding/import/ImportSubAccountsScreen.tsx b/src/features/onboarding/import/ImportSubAccountsScreen.tsx
index 38148e49f..6deb91fe7 100644
--- a/src/features/onboarding/import/ImportSubAccountsScreen.tsx
+++ b/src/features/onboarding/import/ImportSubAccountsScreen.tsx
@@ -9,16 +9,18 @@ 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 { RootNavigationProp } from 'src/app/rootTypes'
+import { AccountsServiceNavigationProp } from 'src/app/services/AccountsService/accountServiceTypes'
+import ScrollBox from '@components/ScrollBox'
import { useOnboarding } from '../OnboardingProvider'
export default () => {
@@ -71,6 +73,13 @@ export default () => {
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ item, index }: { item: ResolvedPath; index: number }) => {
+ const isFirst = index === 0
+ const isLast = index === derivationAccounts.length - 1
+ const borderTopStartRadius = isFirst ? 'xl' : 'none'
+ const borderTopEndRadius = isFirst ? 'xl' : 'none'
+ const borderBottomStartRadius = isLast ? 'xl' : 'none'
+ const borderBottomEndRadius = isLast ? 'xl' : 'none'
+
const onSelect = () => {
if (selected.has(item.derivationPath)) {
selected.delete(item.derivationPath)
@@ -86,29 +95,33 @@ export default () => {
flexDirection="row"
minHeight={72}
alignItems="center"
- paddingHorizontal="m"
- paddingVertical="m"
+ paddingHorizontal="4"
+ paddingVertical="4"
borderBottomColor="primaryBackground"
- borderBottomWidth={index === derivationAccounts.length - 1 ? 0 : 1}
+ borderBottomWidth={index === derivationAccounts.length - 1 ? 0 : 2}
+ borderTopStartRadius={borderTopStartRadius}
+ borderTopEndRadius={borderTopEndRadius}
+ borderBottomStartRadius={borderBottomStartRadius}
+ borderBottomEndRadius={borderBottomEndRadius}
>
-
+
{item.derivationPath}
{ellipsizeAddress(item.keypair.publicKey.toBase58())}
@@ -116,7 +129,7 @@ export default () => {
{(item.tokens?.value.length || 0) > 0 ? (
@@ -125,7 +138,7 @@ export default () => {
) : null}
{(item.nfts?.length || 0) > 0 ? (
@@ -136,7 +149,7 @@ export default () => {
) : null}
{item.needsMigrated ? (
@@ -151,11 +164,11 @@ export default () => {
style={{ height: 18, width: 18 }}
tintColors={{
true: colors.primaryText,
- false: colors.transparent10,
+ false: colors.primaryText,
}}
- onCheckColor={colors.secondary}
+ onCheckColor={colors.primaryBackground}
onTintColor={colors.primaryText}
- tintColor={colors.transparent10}
+ tintColor={colors.primaryText}
onFillColor={colors.primaryText}
onAnimationType="fill"
offAnimationType="fill"
@@ -166,14 +179,7 @@ export default () => {
)
},
- [
- colors.primaryText,
- colors.secondary,
- colors.transparent10,
- derivationAccounts,
- selected,
- t,
- ],
+ [colors, derivationAccounts, selected, t],
)
const keyExtractor = useCallback(
@@ -182,13 +188,13 @@ export default () => {
)
const navigation = useNavigation()
+ const accountsNavigation = useNavigation()
const onNext = useCallback(() => {
if (hasAccounts) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
- navigation.replace('TabBarNavigator', {
- screen: 'Home',
+ accountsNavigation.navigate('AccountAssignScreen', {
params: {
screen: 'AccountAssignScreen',
params: {
@@ -209,57 +215,81 @@ export default () => {
},
})
}
- }, [hasAccounts, navigation, words])
+ }, [hasAccounts, navigation, words, accountsNavigation])
return (
-
-
-
- {t('accountImport.privateKey.selectAccounts')}
-
-
- {t('accountImport.privateKey.selectAccountsBody')}
-
- {error && {error.message}}
- {}}
- title=""
- tintColor={colors.primaryText}
- />
- }
- data={derivationAccounts}
- keyExtractor={keyExtractor}
- renderItem={renderItem}
+
- {}}
+ title=""
+ tintColor={colors.primaryText}
/>
-
-
+ }
+ >
+
+
+
+ {t('accountImport.privateKey.selectAccounts')}
+
+
+ {t('accountImport.privateKey.selectAccountsBody')}
+
+ {error && (
+
+ {error.message}
+
+ )}
+
+
+
+
+
)
}
diff --git a/src/features/onboarding/import/MatchingWord.tsx b/src/features/onboarding/import/MatchingWord.tsx
index 2c49473f7..b174a82d2 100644
--- a/src/features/onboarding/import/MatchingWord.tsx
+++ b/src/features/onboarding/import/MatchingWord.tsx
@@ -22,20 +22,20 @@ const MatchingWord = ({ fullWord, matchingText, onPress }: Props) => {
{upperCase(matchingText)}
-
+
@@ -131,7 +132,7 @@ const PassphraseAutocomplete = ({
onPress={onSubmit}
icon="arrowRight"
backgroundColor={accentKey}
- backgroundColorPressed="surfaceContrast"
+ backgroundColorPressed="primaryBackground"
iconColor="primaryBackground"
backgroundColorOpacityPressed={0.1}
/>
@@ -139,7 +140,7 @@ const PassphraseAutocomplete = ({
)}
-
))}
-
+
>
)
diff --git a/src/features/payment/PaymentCard.tsx b/src/features/payment/PaymentCard.tsx
index 5d3258eb9..ecdf01e3d 100644
--- a/src/features/payment/PaymentCard.tsx
+++ b/src/features/payment/PaymentCard.tsx
@@ -1,22 +1,16 @@
import Box from '@components/Box'
-import SubmitButton from '@components/SubmitButton'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
import { PaymentV2 } from '@helium/transactions'
-import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
-import React, { memo, useCallback, useState } from 'react'
+import React, { memo, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
-import { LayoutChangeEvent } from 'react-native'
-import { useAccountStorage } from '../../storage/AccountStorageProvider'
-import { checkSecureAccount } from '../../storage/secureStorage'
-import animateTransition from '../../utils/animateTransition'
+import ButtonPressable from '@components/ButtonPressable'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { checkSecureAccount } from '@config/storage/secureStorage'
import { SendDetails } from '../../utils/linking'
import PaymentSummary from './PaymentSummary'
type Props = {
- handleCancel: () => void
totalBalance: BN
feeTokenBalance?: BN
onSubmit: (opts?: { txn: PaymentV2; txnJson: string }) => void
@@ -24,10 +18,10 @@ type Props = {
errors?: string[]
payments?: SendDetails[]
mint: PublicKey
+ loading?: boolean
}
const PaymentCard = ({
- handleCancel,
totalBalance,
feeTokenBalance,
onSubmit,
@@ -35,14 +29,12 @@ const PaymentCard = ({
mint,
payments,
errors,
+ loading,
}: Props) => {
- const { symbol } = useMetaplexMetadata(mint)
const { t } = useTranslation()
- const [payEnabled, setPayEnabled] = useState(false)
- const [height, setHeight] = useState(0)
const { currentAccount } = useAccountStorage()
- const handlePayPressed = useCallback(async () => {
+ const handleSubmit = useCallback(async () => {
if (!currentAccount?.ledgerDevice && !currentAccount?.keystoneDevice) {
const hasSecureAccount = await checkSecureAccount(
currentAccount?.address,
@@ -50,35 +42,11 @@ const PaymentCard = ({
)
if (!hasSecureAccount) return
}
- animateTransition('PaymentCard.payEnabled')
- setPayEnabled(true)
- }, [
- currentAccount?.ledgerDevice,
- currentAccount?.address,
- currentAccount?.keystoneDevice,
- ])
-
- const handleLayout = useCallback(
- (e: LayoutChangeEvent) => {
- if (height > 0) return
- setHeight(e.nativeEvent.layout.height)
- },
- [height],
- )
-
- const handleSubmit = onSubmit
+ onSubmit()
+ }, [onSubmit, currentAccount])
return (
-
+
- {!payEnabled ? (
- <>
-
-
-
- {t('generic.cancel')}
-
-
-
-
- {t('payment.pay')}
-
-
-
- >
- ) : (
-
- )}
+ <>
+
+
+
+ >
)
diff --git a/src/features/payment/PaymentError.tsx b/src/features/payment/PaymentError.tsx
index cd48720f0..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'
@@ -49,30 +49,30 @@ const PaymentError = ({
return (
-
+
-
+
{t('payment.submitFailed')}
{!!errorMessage && (
{errorMessage}
)}
-
+
-
+
-
-
+
+
{t('generic.cancel')}
diff --git a/src/features/payment/PaymentItem.tsx b/src/features/payment/PaymentItem.tsx
index a0286bfe7..7bcdce2ba 100644
--- a/src/features/payment/PaymentItem.tsx
+++ b/src/features/payment/PaymentItem.tsx
@@ -1,20 +1,15 @@
-import ContactIcon from '@assets/images/account.svg'
-import Remove from '@assets/images/remove.svg'
-import AccountIcon from '@components/AccountIcon'
-import BackgroundFill from '@components/BackgroundFill'
+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'
import TextInput from '@components/TextInput'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import Address from '@helium/address'
import { useMint } from '@helium/helium-react-hooks'
-import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
import { BoxProps } from '@shopify/restyle'
import { PublicKey } from '@solana/web3.js'
-import { Theme } from '@theme/theme'
-import { useColors, useOpacity } from '@theme/themeHooks'
-import { shortenAddress } from '@utils/formatting'
+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'
@@ -26,7 +21,8 @@ import {
TextInputEndEditingEventData,
} from 'react-native'
import { useDebounce } from 'use-debounce'
-import { CSAccount } from '../../storage/cloudStorage'
+import { shortenAddress } from '@utils/formatting'
+import { CSAccount } from '@config/storage/cloudStorage'
import { useBalance } from '../../utils/Balance'
import {
accountNetType,
@@ -66,7 +62,7 @@ type Props = {
showAmount?: boolean
} & Payment
-const ITEM_HEIGHT = 80
+const ITEM_HEIGHT = 74
const PaymentItem = ({
account,
@@ -92,11 +88,9 @@ const PaymentItem = ({
...boxProps
}: Props) => {
const decimals = useMint(mint)?.info?.decimals
- const { colorStyle } = useOpacity('primaryText', 0.3)
const { dcToNetworkTokens } = useBalance()
const { t } = useTranslation()
const { secondaryText } = useColors()
- const { symbol, loading: loadingMeta } = useMetaplexMetadata(mint)
const [rawAddress, setRawAddress] = useState('')
const [debouncedAddress] = useDebounce(rawAddress, 500)
@@ -194,56 +188,77 @@ const PaymentItem = ({
[account, address],
)
- const AddressIcon = useCallback(() => {
- if (address && Address.isValid(address)) {
- return
+ const toLabel = useMemo(() => {
+ if (address && account?.alias && account?.alias.split('.').length === 2) {
+ return shortenAddress(address, 6)
+ }
+
+ if (account?.alias) {
+ return account?.alias
+ }
+
+ return t('payment.to')
+ }, [account?.alias, address, t])
+
+ const addressLabel = useMemo(() => {
+ if (address && account?.alias && account?.alias.split('.').length === 2) {
+ return rawAddress
+ }
+
+ // TODO: We need to fix this since this does not work if someone adds a contact as cat.sol for example. Requires a refactor to payment screen
+ if (account?.alias && account?.alias.split('.').length !== 2) {
+ return address
}
- return
- }, [address, secondaryText])
+
+ return rawAddress
+ }, [account?.alias, address, rawAddress])
return (
-
- {hasError && }
+
{isDeepLink && address ? (
{ellipsizeAddress(address)}
) : (
-
+
-
-
-
-
- {account?.alias && account?.alias.split('.').length === 2
- ? address && shortenAddress(address, 6)
- : account?.alias}
+
+
+
+ {toLabel}
{isProgramAccount ? (
-
+
{t('payment.programOwnedWarning')}
) : null}
@@ -273,7 +293,7 @@ const PaymentItem = ({
{!!onRemove && (
@@ -281,10 +301,15 @@ const PaymentItem = ({
)}
-
-
{showAmount && (
-
+
{!amount || amount?.isZero() ? (
<>
- {!loadingMeta && (
-
- {t('payment.enterAmount', {
- ticker: symbol,
- })}
-
- )}
+
+ {t('payment.enterAmount')}
+
>
) : (
@@ -314,14 +334,14 @@ const PaymentItem = ({
flex={1}
>
{humanReadable(amount, decimals)}
{fee && (
-
+
{t('payment.fee', {
value: humanReadable(feeAsTokens, 8),
})}
@@ -332,19 +352,22 @@ const PaymentItem = ({
-
+
{toUpper(t('payment.max'))}
diff --git a/src/features/payment/PaymentQrScanner.tsx b/src/features/payment/PaymentQrScanner.tsx
index ac9be631e..74c69fd57 100644
--- a/src/features/payment/PaymentQrScanner.tsx
+++ b/src/features/payment/PaymentQrScanner.tsx
@@ -4,14 +4,16 @@ 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'
+import { SendNavigationProp } from '@services/WalletService/pages/SendPage'
import { parseBurn, parseDelegate, parsePaymentLink } from '../../utils/linking'
-import { HomeNavigationProp } from '../home/homeTypes'
const PaymentQrScanner = () => {
const { triggerNotification } = useHaptic()
const { showOKAlert } = useAlert()
const { t } = useTranslation()
- const navigation = useNavigation()
+ const navigation = useNavigation()
+ const sendNav = useNavigation()
const handleBarCodeScanned = useCallback(
async (data: string) => {
@@ -20,7 +22,7 @@ const PaymentQrScanner = () => {
const delegate = parseDelegate(data)
if (payment) {
triggerNotification('success')
- navigation.navigate('PaymentScreen', payment)
+ sendNav.navigate('PaymentScreen', payment)
} else if (burn) {
navigation.goBack()
navigation.replace('BurnScreen', burn)
@@ -42,7 +44,7 @@ const PaymentQrScanner = () => {
navigation.goBack()
}
},
- [navigation, showOKAlert, t, triggerNotification],
+ [navigation, showOKAlert, t, triggerNotification, sendNav],
)
return
diff --git a/src/features/payment/PaymentScreen.tsx b/src/features/payment/PaymentScreen.tsx
index 0579d2206..fadc09edc 100644
--- a/src/features/payment/PaymentScreen.tsx
+++ b/src/features/payment/PaymentScreen.tsx
@@ -1,15 +1,8 @@
-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 AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
import Box from '@components/Box'
import HNTKeyboard, { HNTKeyboardRef } from '@components/HNTKeyboard'
-import IconPressedContainer from '@components/IconPressedContainer'
import Text from '@components/Text'
import TokenButton from '@components/TokenButton'
import TokenSelector, {
@@ -17,7 +10,7 @@ import TokenSelector, {
TokenSelectorRef,
} from '@components/TokenSelector'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import Address, { NetTypes } from '@helium/address'
+import Address from '@helium/address'
import { useMint, useOwnedAmount } from '@helium/helium-react-hooks'
import { DC_MINT, HNT_MINT, truthy } from '@helium/spl-utils'
import useDisappear from '@hooks/useDisappear'
@@ -26,8 +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 { useColors, useHitSlop } from '@theme/themeHooks'
+import { useVisibleTokens } from '@config/storage/TokensProvider'
import { Mints } from '@utils/constants'
import { fetchDomainOwner } from '@utils/getDomainOwner'
import {
@@ -45,31 +37,31 @@ import React, {
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
-import { Keyboard, Platform } from 'react-native'
+import { Image, Keyboard, Platform } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
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'
+import { PaymentRouteParam } from 'src/app/services/WalletService'
+import ScrollBox from '@components/ScrollBox'
+import {
+ SendNavigationProp,
+ SendStackParamList,
+} 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'
-import {
- accountNetType,
- formatAccountAlias,
- solAddressIsValid,
-} from '../../utils/accountUtils'
+import { accountNetType, solAddressIsValid } from '../../utils/accountUtils'
import { SendDetails } from '../../utils/linking'
import * as logger from '../../utils/logger'
-import {
- HomeNavigationProp,
- HomeStackParamList,
- PaymentRouteParam,
-} from '../home/homeTypes'
import PaymentCard from './PaymentCard'
import PaymentItem from './PaymentItem'
import PaymentSubmit from './PaymentSubmit'
@@ -105,16 +97,18 @@ const parseLinkedPayments = (opts: PaymentRouteParam): LinkedPayment[] => {
return []
}
-type Route = RouteProp
+type Route = RouteProp
const PaymentScreen = () => {
const route = useRoute()
+ const { bottom } = useSafeAreaInsets()
const addressBookRef = useRef(null)
- const accountSelectorRef = useRef(null)
const tokenSelectorRef = useRef(null)
const hntKeyboardRef = useRef(null)
const { visibleTokens } = useVisibleTokens()
const inputMint = usePublicKey(route.params?.mint)
+
const [mint, setMint] = useState(inputMint || HNT_MINT)
+
const {
currentAccount,
currentNetworkAddress,
@@ -138,16 +132,21 @@ const PaymentScreen = () => {
const { anchorProvider, connection } = useSolana()
const appDispatch = useAppDispatch()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const rootNav = useNavigation()
+ const sendNav = useNavigation()
const { t } = useTranslation()
- const { primaryText } = useColors()
- const hitSlop = useHitSlop('l')
useDisappear(() => {
appDispatch(solanaSlice.actions.resetPayment())
})
+ useEffect(() => {
+ if (!inputMint) return
+ appDispatch(solanaSlice.actions.resetPayment())
+ setMint(inputMint)
+ }, [inputMint, appDispatch])
+
const navBack = useCallback(() => {
if (navigation.canGoBack()) {
navigation.goBack()
@@ -156,7 +155,7 @@ const PaymentScreen = () => {
} else {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
}
}, [navigation, rootNav])
@@ -268,9 +267,9 @@ const PaymentScreen = () => {
[currentAccount?.address, dispatch],
)
- const handleQrScan = useCallback(() => {
- navigation.navigate('PaymentQrScanner')
- }, [navigation])
+ // const handleQrScan = useCallback(() => {
+ // navigation.navigate('PaymentQrScanner')
+ // }, [navigation])
const canAddPayee = useMemo(() => {
if (currentAccount?.ledgerDevice) {
@@ -302,25 +301,27 @@ const PaymentScreen = () => {
[paymentState.payments],
)
- const handleSubmit = useCallback(async () => {
- try {
- await submitPayment(
- paymentState.payments
- .filter((p) => p.address && p.amount)
- .map((payment) => ({
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- payee: payment.address!,
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- balanceAmount: payment.amount!,
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- max: payment.max!,
- })),
- paymentState.mint,
- )
- } catch (e) {
- logger.error(e)
- }
- }, [submitPayment, paymentState.mint, paymentState.payments])
+ const { execute: handleSubmit, loading: submitLoading } = useAsyncCallback(
+ async () => {
+ try {
+ await submitPayment(
+ paymentState.payments
+ .filter((p) => p.address && p.amount)
+ .map((payment) => ({
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ payee: payment.address!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ balanceAmount: payment.amount!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ max: payment.max!,
+ })),
+ paymentState.mint,
+ )
+ } catch (e) {
+ logger.error(e)
+ }
+ },
+ )
const insufficientFunds = useMemo((): [
value: boolean,
@@ -640,23 +641,15 @@ const PaymentScreen = () => {
}
}, [navigation, top])
- const handleShowAccounts = useCallback(() => {
- if (!accountSelectorRef?.current) return
-
- let accts = [] as CSAccount[]
- accts = sortedAccountsForNetType(NetTypes.MAINNET)
- if (accts.length < 2) return
-
- const netType = NetTypes.MAINNET
-
- accountSelectorRef?.current.showAccountTypes(netType)()
- }, [sortedAccountsForNetType])
-
const decimals = useMint(mint)?.info?.decimals
const tokenButtonBalance = useMemo(() => {
return humanReadable(balance, decimals)
}, [balance, decimals])
+ const onSuccess = useCallback(() => {
+ sendNav.replace('PaymentScreen')
+ }, [sendNav])
+
const data = useMemo((): TokenListItem[] => {
const tokens = [...visibleTokens]
.filter(truthy)
@@ -669,174 +662,148 @@ const PaymentScreen = () => {
}, [mint, visibleTokens])
return (
- <>
-
+
-
-
-
-
+ {/*
-
-
-
-
-
-
-
+
- {t('payment.send')}
-
-
-
-
-
-
+
+
-
-
- 1
- }
- address={currentAccount?.address}
- onPress={handleShowAccounts}
- showBubbleArrow
- marginHorizontal="l"
- marginBottom="xs"
- />
-
-
-
- {paymentState.payments.map((p, index) => (
- // eslint-disable-next-line react/no-array-index-key
-
- 1
- ? handleRemove
- : undefined
- }
- netType={networkType}
- showAmount
- />
-
- ))}
- {canAddPayee && (
-
-
- {t('payment.addRecipient')}
-
-
- )}
-
-
-
-
-
-
-
-
-
- >
+ */}
+
+
+
+
+ {t('payment.send')}
+
+
+ {t('payment.sendTokensToAnyAddress')}
+
+
+
+
+
+ {paymentState.payments.map((p, index) => (
+ // eslint-disable-next-line react/no-array-index-key
+
+ 1 ? handleRemove : undefined
+ }
+ netType={networkType}
+ showAmount
+ />
+
+ ))}
+ {canAddPayee && (
+
+
+ {t('payment.addRecipient')}
+
+
+ )}
+
+
+
+
+
+
+
+
)
}
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 b4821d106..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
@@ -45,10 +45,10 @@ const PaymentSubmitLoading = ({ onVideoEnd }: Props) => {
{t('payment.sending')}
diff --git a/src/features/payment/PaymentSuccess.tsx b/src/features/payment/PaymentSuccess.tsx
index a7ea9b5b0..ef81c5df9 100644
--- a/src/features/payment/PaymentSuccess.tsx
+++ b/src/features/payment/PaymentSuccess.tsx
@@ -1,5 +1,4 @@
-import SuccessIcon from '@assets/images/paymentSuccess.svg'
-import BackgroundFill from '@components/BackgroundFill'
+import SuccessIcon from '@assets/svgs/paymentSuccess.svg'
import Box from '@components/Box'
import Text from '@components/Text'
import TouchableOpacityBox from '@components/TouchableOpacityBox'
@@ -7,6 +6,8 @@ import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
import React, { memo } from 'react'
import { useTranslation } from 'react-i18next'
+import { NavBarHeight } from '@components/ServiceNavBar'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { Payment } from './PaymentItem'
import PaymentSummary from './PaymentSummary'
@@ -28,21 +29,26 @@ const PaymentSuccess = ({
mint,
}: Props) => {
const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+
return (
-
-
+
+
-
+
{t('payment.submitSuccess')}
-
-
+
{actionTitle}
diff --git a/src/features/payment/PaymentSummary.tsx b/src/features/payment/PaymentSummary.tsx
index 429091bf7..9ccea3a7b 100644
--- a/src/features/payment/PaymentSummary.tsx
+++ b/src/features/payment/PaymentSummary.tsx
@@ -68,9 +68,9 @@ const PaymentSummary = ({
key="ellipsis"
style={{ marginLeft: MAX_ACCOUNT_ICONS * -4 }}
width={16}
- borderRadius="round"
+ borderRadius="full"
height={16}
- backgroundColor="black300"
+ backgroundColor="gray.true-700"
flexDirection="row"
alignItems="center"
justifyContent="space-evenly"
@@ -78,20 +78,20 @@ const PaymentSummary = ({
,
)
@@ -102,10 +102,10 @@ const PaymentSummary = ({
return (
<>
-
+
{t('payment.total')}
-
+
{total}
@@ -114,17 +114,22 @@ const PaymentSummary = ({
{showRecipients && payments.length > 0 && (
<>
{accountIcons}
-
+
{t('payment.totalRecipients', { count: payments.length })}
>
)}
{!!errors?.length && (
-
+
{errors[0]}
)}
-
+
{fee}
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/request/RequestScreen.tsx b/src/features/request/RequestScreen.tsx
deleted file mode 100644
index 85ec79e17..000000000
--- a/src/features/request/RequestScreen.tsx
+++ /dev/null
@@ -1,392 +0,0 @@
-import ShareIcon from '@assets/images/share.svg'
-import AccountButton from '@components/AccountButton'
-import AccountSelector, {
- AccountSelectorRef,
-} from '@components/AccountSelector'
-import BackgroundFill from '@components/BackgroundFill'
-import Box from '@components/Box'
-import FadeInOut from '@components/FadeInOut'
-import HNTKeyboard, { HNTKeyboardRef } from '@components/HNTKeyboard'
-import TabBar, { TabBarOption } from '@components/TabBar'
-import Text from '@components/Text'
-import TokenButton from '@components/TokenButton'
-import TokenSelector, {
- TokenListItem,
- TokenSelectorRef,
-} from '@components/TokenSelector'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { NetTypes as NetType } from '@helium/address'
-import { useMint } from '@helium/helium-react-hooks'
-import useHaptic from '@hooks/useHaptic'
-import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
-import Clipboard from '@react-native-community/clipboard'
-import { useKeyboard } from '@react-native-community/hooks'
-import { useNavigation } from '@react-navigation/native'
-import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { useVisibleTokens } from '@storage/TokensProvider'
-import {
- useBorderRadii,
- useColors,
- useOpacity,
- useSpacing,
-} from '@theme/themeHooks'
-import animateTransition from '@utils/animateTransition'
-import { makePayRequestLink } from '@utils/linking'
-import { humanReadable } from '@utils/solanaUtils'
-import BN from 'bn.js'
-import React, {
- memo,
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react'
-import { useTranslation } from 'react-i18next'
-import {
- ActivityIndicator,
- Keyboard,
- LayoutChangeEvent,
- Platform,
-} from 'react-native'
-import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
-import QRCode from 'react-native-qrcode-svg'
-import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
-import Share, { ShareOptions } from 'react-native-share'
-import Toast from 'react-native-simple-toast'
-import { useDebounce } from 'use-debounce'
-
-const QR_CONTAINER_SIZE = 220
-
-type RequestType = 'qr' | 'link'
-const RequestScreen = () => {
- const { visibleTokens } = useVisibleTokens()
- const { currentAccount, currentNetworkAddress: networkAddress } =
- useAccountStorage()
- const { t } = useTranslation()
- const [requestType, setRequestType] = useState('qr')
- const [containerHeight, setContainerHeight] = useState(0)
- const { colorStyle } = useOpacity('primaryText', 0.3)
- const accountSelectorRef = useRef(null)
- const { triggerNavHaptic } = useHaptic()
- const navigation = useNavigation()
- const { l } = useSpacing()
- const { l: borderRadius } = useBorderRadii()
- const { secondaryText, primaryText } = useColors()
- const [isEditing, setIsEditing] = useState(false)
- const { keyboardShown } = useKeyboard()
- const hntKeyboardRef = useRef(null)
- const [hntKeyboardVisible, setHNTKeyboardVisible] = useState(false)
- const [paymentAmount, setPaymentAmount] = useState()
- const [mint, setMint] = useState()
- const tokenSelectorRef = useRef(null)
- const qrRef = useRef<{
- toDataURL: (callback: (url: string) => void) => void
- }>(null)
- const decimals = useMint(mint)?.info?.decimals
- const { symbol } = useMetaplexMetadata(mint)
-
- const handleBalance = useCallback(
- (opts: { balance: BN; payee?: string; index?: number }) => {
- setPaymentAmount(opts.balance)
- },
- [setPaymentAmount],
- )
-
- const handleRequestTypePress = useCallback((type: string) => {
- setRequestType(type as RequestType)
- }, [])
-
- const handleShowPaymentKeyboard = useCallback(() => {
- Keyboard.dismiss()
- hntKeyboardRef.current?.show({
- payee: currentAccount,
- payer: null,
- containerHeight,
- balance: paymentAmount,
- })
- }, [containerHeight, currentAccount, paymentAmount])
-
- const handleContainerLayout = useCallback(
- (layout: LayoutChangeEvent) =>
- setContainerHeight(layout.nativeEvent.layout.height),
- [],
- )
-
- const link = useMemo(() => {
- if (!networkAddress) return ''
-
- return makePayRequestLink({
- payee: networkAddress,
- balanceAmount: paymentAmount,
- mint: mint?.toBase58(),
- })
- }, [networkAddress, paymentAmount, mint])
-
- const [qrLink] = useDebounce(link, 500)
-
- const qrStyle = useAnimatedStyle(() => {
- const opac = requestType === 'qr' && !!qrLink && !keyboardShown ? 1 : 0
- const animVal = withTiming(opac, { duration: 300 })
- return {
- opacity: animVal,
- position: 'absolute',
- height: QR_CONTAINER_SIZE,
- justifyContent: 'center',
- alignSelf: 'center',
- backgroundColor: primaryText,
- aspectRatio: 1,
- padding: l,
- borderRadius,
- }
- }, [requestType, qrLink, keyboardShown])
-
- useEffect(() => {
- const nextEditing = qrLink !== link || keyboardShown || hntKeyboardVisible
- if (nextEditing === isEditing) return
-
- animateTransition('RequestScreen.Editing')
- setIsEditing(nextEditing)
- }, [hntKeyboardVisible, isEditing, keyboardShown, link, qrLink])
-
- const showToast = useCallback(() => {
- Toast.show(
- t('request.copied', {
- target: link,
- }),
- )
- }, [link, t])
-
- const handleShare = useCallback(async () => {
- qrRef.current?.toDataURL((imgData) => {
- const imageUrl = `data:image/png;base64,${imgData}`
-
- let options: ShareOptions = {
- failOnCancel: false,
- title: 'image',
- message: link,
- url: imageUrl,
- type: 'image/png',
- }
-
- if (Platform.OS === 'ios') {
- options = {
- failOnCancel: false,
- message: link,
- url: imageUrl,
- type: 'image/png',
- activityItemSources: [
- {
- item: {},
- placeholderItem: { type: 'text', content: link },
- linkMetadata: {
- title: link,
- },
- },
- ],
- }
- }
- Share.open(options)
- })
- }, [link])
-
- const copyLink = useCallback(() => {
- Clipboard.setString(link)
- showToast()
- triggerNavHaptic()
- }, [link, showToast, triggerNavHaptic])
-
- const requestTypeOptions = useMemo(
- (): Array => [
- { title: t('request.qr'), value: 'qr' },
- { title: t('request.link'), value: 'link' },
- ],
- [t],
- )
-
- const handleTickerSelected = useCallback(() => {
- tokenSelectorRef?.current?.showTokens()
- }, [])
-
- const handleAccountButtonPress = useCallback(() => {
- if (!accountSelectorRef?.current) return
- accountSelectorRef?.current?.show()
- }, [])
-
- const data = useMemo((): TokenListItem[] => {
- return [...visibleTokens].map((m) => {
- return {
- selected: mint?.toBase58() === m,
- mint: new PublicKey(m),
- }
- })
- }, [visibleTokens, mint])
-
- return (
-
-
-
-
-
- {t('request.title')}
-
-
-
-
-
-
- {!isEditing ? (
-
- ) : (
-
- )}
-
-
- {requestType === 'link' && (
-
-
-
- {link}
-
-
-
- )}
-
-
-
-
-
-
-
- {t('request.amount')}
-
- {!paymentAmount || paymentAmount.isZero() ? (
-
- {t('request.enterAmount', {
- ticker: symbol,
- })}
-
- ) : (
-
- {humanReadable(paymentAmount, decimals)}
-
- )}
-
-
-
-
-
-
- {t('generic.cancel')}
-
-
-
-
-
- {t('generic.share')}
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default memo(RequestScreen)
diff --git a/src/features/settings/AutoGasManager.tsx b/src/features/settings/AutoGasManager.tsx
index c9455370a..8be765507 100644
--- a/src/features/settings/AutoGasManager.tsx
+++ b/src/features/settings/AutoGasManager.tsx
@@ -6,14 +6,16 @@ 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'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
const AutoGasManager: FC = () => {
const { visibleTokens } = useVisibleTokens()
+ const { bottom } = useSafeAreaInsets()
const navigation = useNavigation()
const validInputMints = useMemo(
() =>
@@ -40,23 +42,18 @@ const AutoGasManager: FC = () => {
}, [updateAutoGasManagementToken, inputMint, navigation])
return (
-
+
-
-
- {t('settings.autoGasManagement.title')}
-
-
-
+
@@ -65,20 +62,20 @@ const AutoGasManager: FC = () => {
-
+
{t('settings.autoGasManagement.enabled')}
@@ -86,22 +83,22 @@ const AutoGasManager: FC = () => {
{inputMint && (
{t('settings.autoGasManagement.selectTokenBody')}
-
+
{validInputMints.map((mint) => (
))}
@@ -111,27 +108,27 @@ const AutoGasManager: FC = () => {
navigation.goBack()}
/>
{
const { t } = useTranslation()
const navigation = useNavigation<
- HomeNavigationProp & SettingsNavigationProp
+ WalletNavigationProp & SettingsNavigationProp
>()
const rootNav = useNavigation()
const { showOKCancelAlert } = useAlert()
@@ -109,7 +109,7 @@ const ConfirmSignoutScreen = () => {
if (!mnemonic) return null
return (
-
+
{mnemonic ? (
{
const { currentAccount } = useAccountStorage()
const { t } = useTranslation()
- const navigation = useNavigation()
const [privateKey, setPrivateKey] = useState()
const [revealed, setRevealed] = useState(false)
const { showOKCancelAlert } = useAlert()
@@ -28,7 +26,7 @@ const RevealPrivateKeyScreen = () => {
const secureAccount = await getSecureAccount(currentAccount.address)
if (!secureAccount?.keypair.sk) return
setPrivateKey(
- JSON.stringify(
+ bs58.encode(
Buffer.from(secureAccount?.keypair?.sk, 'base64').toJSON().data,
),
)
@@ -44,30 +42,31 @@ const RevealPrivateKeyScreen = () => {
return (
-
+
{t('settings.revealPrivateKey.title')}
{revealed ? (
<>
@@ -80,16 +79,17 @@ const RevealPrivateKeyScreen = () => {
{
)}
-
)
}
diff --git a/src/features/settings/RevealWordsScreen.tsx b/src/features/settings/RevealWordsScreen.tsx
index bb7340885..ed436a114 100644
--- a/src/features/settings/RevealWordsScreen.tsx
+++ b/src/features/settings/RevealWordsScreen.tsx
@@ -2,12 +2,13 @@ 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'
const RevealWordsScreen = () => {
const { currentAccount } = useAccountStorage()
@@ -24,15 +25,15 @@ const RevealWordsScreen = () => {
const ListHeaderComponent = useMemo(() => {
return (
{
}, [mnemonic?.length])
return (
-
-
-
+
+
+
+
+
)
}
diff --git a/src/features/settings/Settings.tsx b/src/features/settings/Settings.tsx
index 47eae4807..4f8b8d721 100644
--- a/src/features/settings/Settings.tsx
+++ b/src/features/settings/Settings.tsx
@@ -1,7 +1,5 @@
import Box from '@components/Box'
-import CloseButton from '@components/CloseButton'
import ImageBox from '@components/ImageBox'
-import SafeAreaBox from '@components/SafeAreaBox'
import Text from '@components/Text'
import { truthy } from '@helium/spl-utils'
import useAlert from '@hooks/useAlert'
@@ -9,41 +7,42 @@ import { useAppVersion } from '@hooks/useDevice'
import { useExplorer } from '@hooks/useExplorer'
import { useNavigation } from '@react-navigation/native'
import { Cluster } from '@solana/web3.js'
-import { useHitSlop, 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 { 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 ScrollBox from '@components/ScrollBox'
+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'
-import { HomeNavigationProp } from '../home/homeTypes'
import SettingsListItem, { SettingsListItemType } from './SettingsListItem'
import { SettingsNavigationProp } from './settingsTypes'
import useAuthIntervals from './useAuthIntervals'
const Settings = () => {
const { t } = useTranslation()
- const homeNav = useNavigation()
+ const homeNav = useNavigation()
const settingsNav = useNavigation()
const rootNav = useNavigation()
const spacing = useSpacing()
const version = useAppVersion()
const buildNumber = deviceInfo.getBuildNumber()
- const hitSlop = useHitSlop('xxl')
const authIntervals = useAuthIntervals()
+ const colors = useColors()
const {
currentAccount,
accounts,
@@ -76,16 +75,12 @@ const Settings = () => {
() => appPin !== undefined && appPin.status !== 'off',
[appPin],
)
-
- const onRequestClose = useCallback(() => {
- homeNav.navigate('AccountsScreen')
- }, [homeNav])
-
const contentContainer = useMemo(
() => ({
- paddingBottom: spacing.xxxl,
+ paddingBottom: spacing['15'],
+ marginTop: spacing['6xl'],
}),
- [spacing.xxxl],
+ [spacing],
)
const keyExtractor = useCallback((item, index) => item.title + index, [])
@@ -321,7 +316,7 @@ const Settings = () => {
}, [settingsNav])
const handlePressAutoGasManager = useCallback(() => {
- settingsNav.navigate('AutoGasManager')
+ settingsNav.push('AutoGasManager')
}, [settingsNav])
const handleMigrateWallet = useCallback(() => {
@@ -601,39 +596,40 @@ const Settings = () => {
)
const renderSectionHeader = useCallback(
- ({ section: { title, icon } }) => (
-
- {icon !== undefined && icon}
-
- {title}
-
-
- ),
- [],
+ ({ section: { title, icon } }) => {
+ const firstSection =
+ title ===
+ t('settings.sections.account.title', {
+ alias: currentAccount?.alias,
+ })
+
+ return (
+
+ {icon !== undefined && icon}
+
+ {title}
+
+
+ )
+ },
+ [currentAccount, t],
)
return (
-
-
- {t('settings.title')}
-
-
+
{
// ^ Sometimes on initial page load there is a bug with SectionList
// where it won't render all items right away. This seems to fix it.
/>
-
+
)
}
diff --git a/src/features/settings/SettingsConfirmPinScreen.tsx b/src/features/settings/SettingsConfirmPinScreen.tsx
index 243c79552..f243b1ba3 100644
--- a/src/features/settings/SettingsConfirmPinScreen.tsx
+++ b/src/features/settings/SettingsConfirmPinScreen.tsx
@@ -2,7 +2,9 @@ import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { RouteProp, useRoute, useNavigation } from '@react-navigation/native'
import ConfirmPinView from '@components/ConfirmPinView'
-import { useAppStorage } from '../../storage/AppStorageProvider'
+import { ThemeProvider } from '@shopify/restyle'
+import { darkTheme } from '@config/theme/theme'
+import { useAppStorage } from '@config/storage/AppStorageProvider'
import { SettingsNavigationProp, SettingsStackParamList } from './settingsTypes'
type Route = RouteProp
@@ -86,4 +88,12 @@ const SettingsConfirmPinScreen = () => {
)
}
-export default SettingsConfirmPinScreen
+const SettingsConfirmPinScreenWrapper = () => {
+ return (
+
+
+
+ )
+}
+
+export default SettingsConfirmPinScreenWrapper
diff --git a/src/features/settings/SettingsCreatePinScreen.tsx b/src/features/settings/SettingsCreatePinScreen.tsx
index a8ee158a9..2e6b9e5e0 100644
--- a/src/features/settings/SettingsCreatePinScreen.tsx
+++ b/src/features/settings/SettingsCreatePinScreen.tsx
@@ -6,6 +6,8 @@ import PinDisplay from '@components/PinDisplay'
import Keypad from '@components/Keypad'
import Box from '@components/Box'
import { KeypadInput } from '@components/KeypadButton'
+import { ThemeProvider } from '@shopify/restyle'
+import { darkTheme } from '@config/theme/theme'
import { SettingsNavigationProp } from './settingsTypes'
const SettingsCreatePinScreen = () => {
@@ -43,29 +45,42 @@ const SettingsCreatePinScreen = () => {
{t('accountSetup.createPin.title')}
-
+
{t('accountSetup.createPin.subtitle')}
-
+
)
}
-export default SettingsCreatePinScreen
+const SettingsCreatePinScreenWrapper = () => {
+ return (
+
+
+
+ )
+}
+
+export default SettingsCreatePinScreenWrapper
diff --git a/src/features/settings/SettingsListItem.tsx b/src/features/settings/SettingsListItem.tsx
index deb727934..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'
@@ -74,7 +74,7 @@ const SettingsListItem = ({
}
const trackColor = useMemo(
- () => ({ false: colors.grey900, true: colors.greenBright500 }),
+ () => ({ false: colors['gray.900'], true: colors['green.light-500'] }),
[colors],
)
@@ -88,9 +88,9 @@ const SettingsListItem = ({
const actionSheetTextProps = useMemo(
() =>
({
- variant: 'regular',
+ variant: 'textMdRegular',
fontSize: 16,
- color: 'surfaceSecondaryText',
+ color: 'secondaryText',
} as TextProps),
[],
)
@@ -107,9 +107,9 @@ const SettingsListItem = ({
)
let textColor: Color = 'primaryText'
- if (destructive && !disabled) textColor = 'red300'
- if (destructive && disabled) textColor = 'red400'
- if (!destructive && disabled) textColor = 'grey400'
+ if (destructive && !disabled) textColor = 'error.500'
+ if (destructive && disabled) textColor = 'error.300'
+ if (!destructive && disabled) textColor = 'gray.400'
const handleSelect = useCallback(
async (itemValue: string | number, itemIndex: number) => {
@@ -127,41 +127,41 @@ const SettingsListItem = ({
justifyContent="space-between"
alignItems="center"
minHeight={56}
- paddingHorizontal="l"
- marginBottom="xxxs"
+ paddingHorizontal="6"
+ marginBottom="0.25"
onPress={handlePress}
disabled={disabled || !(onPress || openUrl || select)}
- borderBottomColor="black"
+ borderBottomColor="border.secondary"
borderBottomWidth={1}
- borderTopColor="black"
+ borderTopColor="border.secondary"
borderTopWidth={isTop ? 1 : 0}
>
{renderModal && renderModal()}
{label}
-
+
{title}
{helperText}
{!onToggle && !select && onPress && (
-
+
)}
- {openUrl && }
+ {openUrl && }
{onToggle && (
)}
{staticText && (
-
+
{value}
)}
diff --git a/src/features/settings/SettingsNavigator.tsx b/src/features/settings/SettingsNavigator.tsx
index 0253616ac..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'
@@ -55,15 +55,10 @@ const SettingsNavigator = () => {
component={SettingsCreatePinScreen}
options={{ presentation: 'modal' }}
/>
-
+
{
-
+
)
}
diff --git a/src/features/settings/ShareAddressScreen.tsx b/src/features/settings/ShareAddressScreen.tsx
index b112ce66e..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'
@@ -22,7 +22,7 @@ const ShareAddressScreen = () => {
const { currentAccount } = useAccountStorage()
const { triggerNavHaptic } = useHaptic()
const spacing = useSpacing()
- const padding = useMemo(() => 'l' as Spacing, [])
+ const padding = useMemo(() => 'xl' as Spacing, [])
const { t } = useTranslation()
const qrRef = useRef<{
toDataURL: (callback: (url: string) => void) => void
@@ -82,13 +82,13 @@ const ShareAddressScreen = () => {
flex={1}
justifyContent="center"
alignItems="center"
- marginBottom="xxxl"
+ marginBottom="15"
>
{currentAccount.alias}
@@ -101,10 +101,10 @@ const ShareAddressScreen = () => {
}
>
{ellipsizeAddress(address)}
@@ -112,9 +112,9 @@ const ShareAddressScreen = () => {
{
{
>
{
@@ -36,27 +35,30 @@ const UpdateAliasScreen = () => {
-
-
- {t('accountAssign.title')}
-
+
{
autoCapitalize: 'words',
}}
fontSize={24}
- marginLeft="m"
- marginRight="xl"
/>
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 87%
rename from src/solana/CollapsibleWritableAccountPreview.tsx
rename to src/features/solana/CollapsibleWritableAccountPreview.tsx
index 1e3c7d004..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'
@@ -36,7 +36,7 @@ const TokenChange = ({
return (
-
+
{symbol}
@@ -132,7 +132,7 @@ export const CollapsibleWritableAccountPreview = ({
return (
setExpanded(!expanded)}>
{writableAccount.name.startsWith('Unknown') ? (
-
+
) : (
)}
-
+
{writableAccount.name}
)}
-
+
{shortenAddress(writableAccount.address.toBase58())}
@@ -205,7 +211,7 @@ export const CollapsibleWritableAccountPreview = ({
) : null}
-
+
{expanded ? (
diff --git a/src/solana/CollectablePreview.tsx b/src/features/solana/CollectablePreview.tsx
similarity index 73%
rename from src/solana/CollectablePreview.tsx
rename to src/features/solana/CollectablePreview.tsx
index 1d3811978..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
@@ -26,40 +26,42 @@ export const CollectablePreview = ({
return (
-
+
{metadata && (
)}
- {ellipsizeAddress(payee)}
+ {ellipsizeAddress(payee)}
diff --git a/src/solana/MessagePreview.tsx b/src/features/solana/MessagePreview.tsx
similarity index 55%
rename from src/solana/MessagePreview.tsx
rename to src/features/solana/MessagePreview.tsx
index 601c58676..5463028ec 100644
--- a/src/solana/MessagePreview.tsx
+++ b/src/features/solana/MessagePreview.tsx
@@ -12,16 +12,20 @@ export const MessagePreview = ({
message,
}: IMransactionPreviewProps) => (
- {message && {message}}
+ {message && (
+
+ {message}
+
+ )}
{warning && (
-
+
{warning}
)}
diff --git a/src/solana/PaymentPreview.tsx b/src/features/solana/PaymentPreview.tsx
similarity index 76%
rename from src/solana/PaymentPreview.tsx
rename to src/features/solana/PaymentPreview.tsx
index f24468c55..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'
@@ -26,12 +26,12 @@ export const PaymentPreivew = ({ mint, payments }: IPaymentPreviewProps) => {
return (
{payments.map(({ payee, balanceAmount }, index) => (
{
flexDirection="row"
alignItems="center"
>
-
+
{json?.image ? : null}
- {symbol}
- {ellipsizeAddress(payee)}
+
+ {symbol}
+
+
+ {ellipsizeAddress(payee)}
+
{
diff --git a/src/solana/SwapPreview.tsx b/src/features/solana/SwapPreview.tsx
similarity index 71%
rename from src/solana/SwapPreview.tsx
rename to src/features/solana/SwapPreview.tsx
index ad20201d4..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,6 +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 '@config/theme/themeHooks'
interface ISwapPreviewProps {
inputMint: PublicKey
@@ -36,15 +37,16 @@ export const SwapPreview = ({
symbol: outputMintSymbol,
json: outputMintJson,
} = useMetaplexMetadata(outputMint)
+ const colors = useColors()
return (
{loadingInputMintMetadata || loadingOutputMintMetadata ? (
@@ -55,11 +57,13 @@ export const SwapPreview = ({
flexDirection="row"
alignItems="center"
>
-
+
{inputMintJson ? (
) : null}
- {inputMintSymbol}
+
+ {inputMintSymbol}
+
@@ -70,17 +74,22 @@ export const SwapPreview = ({
flexDirection="row"
alignItems="center"
>
-
+
{outputMintJson ? (
) : null}
- {outputMintSymbol}
+
+ {outputMintSymbol}
+
@@ -89,8 +98,10 @@ export const SwapPreview = ({
alignItems="center"
justifyContent="space-between"
>
- Min Received due to slippage:
-
+
+ Min Received due to slippage:
+
+
{`~${minReceived.toFixed(outputDecimals)}`}
diff --git a/src/solana/WalletSIgnBottomSheetSimulated.tsx b/src/features/solana/WalletSIgnBottomSheetSimulated.tsx
similarity index 78%
rename from src/solana/WalletSIgnBottomSheetSimulated.tsx
rename to src/features/solana/WalletSIgnBottomSheetSimulated.tsx
index 7037e0f29..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'
@@ -25,6 +25,8 @@ import React, { useCallback, useMemo, useState } from 'react'
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 '@config/theme/themeHooks'
import { useSolana } from './SolanaProvider'
import WalletSignBottomSheetTransaction from './WalletSignBottomSheetTransaction'
import {
@@ -53,6 +55,7 @@ export const WalletSignBottomSheetSimulated = ({
onCancel,
}: IWalletSignBottomSheetSimulatedProps) => {
const { t } = useTranslation()
+ const colors = useColors()
const { connection, cluster } = useSolana()
const wallet = useCurrentWallet()
const solBalance = useBN(useSolOwnedAmount(wallet).amount)
@@ -173,7 +176,7 @@ export const WalletSignBottomSheetSimulated = ({
}
return a
- }, 'warning')
+ }, 'warning.500')
}
return 'critical'
}, [simulationResults])
@@ -199,17 +202,17 @@ export const WalletSignBottomSheetSimulated = ({
totalWarnings && !suppressWarnings && worstSeverity === 'critical'
return (
-
+
{header || url ? (
-
+
{header ? (
-
+
{header}
) : null}
{url ? (
@@ -221,30 +224,38 @@ export const WalletSignBottomSheetSimulated = ({
{type === WalletStandardMessageTypes.connect && (
-
-
-
+
+
+
{t('browserScreen.connectBullet1')}
-
-
+
+
{t('browserScreen.connectBullet2')}
{t('browserScreen.connectToWebsitesYouTrust')}
@@ -257,12 +268,12 @@ export const WalletSignBottomSheetSimulated = ({
{warning && (
-
+
{warning}
@@ -271,30 +282,35 @@ export const WalletSignBottomSheetSimulated = ({
-
+
{t('browserScreen.estimatedChanges')}
setInfoVisible((prev) => !prev)}
>
-
+
{infoVisible && (
-
+
{t('browserScreen.estimatedChangesDescription')}
)}
{!(insufficientFunds || insufficientRentExempt) && message && (
-
+
{message}
)}
{showWarnings ? (
@@ -310,7 +326,7 @@ export const WalletSignBottomSheetSimulated = ({
{(insufficientFunds || insufficientRentExempt) && (
@@ -330,44 +346,48 @@ export const WalletSignBottomSheetSimulated = ({
-
+
{t('browserScreen.writableAccounts')}
setWritableInfoVisible((prev) => !prev)}
>
-
+
-
+
{t('browserScreen.transactions', {
num: simulationResults?.length || 1,
})}
{writableInfoVisible && (
-
+
{t('browserScreen.writableAccountsDescription')}
)}
-
+
{loading && }
{error ? (
-
+
{error.message || error.toString()}
@@ -389,12 +409,12 @@ export const WalletSignBottomSheetSimulated = ({
{hasMore && (
@@ -408,51 +428,51 @@ export const WalletSignBottomSheetSimulated = ({
setFeesExpanded(!feesExpanded)}
- marginTop="s"
+ marginTop="2"
flexDirection="row"
justifyContent="space-between"
>
-
+
{t('browserScreen.totalNetworkFee')}
-
+
{`~${estimatedTotalSol} SOL`}
-
+
{feesExpanded ? (
-
+
-
+
{t('browserScreen.totalBaseFee')}
-
+
{`~${estimatedTotalBaseFee} SOL`}
-
+
{t('browserScreen.totalPriorityFee')}
-
+
{`~${estimatedTotalPriorityFee} SOL`}
@@ -468,12 +488,12 @@ export const WalletSignBottomSheetSimulated = ({
flexDirection="row"
justifyContent="flex-start"
alignItems="center"
- mt={feesExpanded ? 's' : 'm'}
+ mt={feesExpanded ? '2' : '4'}
>
@@ -499,26 +519,26 @@ export const WalletSignBottomSheetSimulated = ({
)}
-
+
)
}
diff --git a/src/solana/WalletSignBottomSheet.tsx b/src/features/solana/WalletSignBottomSheet.tsx
similarity index 62%
rename from src/solana/WalletSignBottomSheet.tsx
rename to src/features/solana/WalletSignBottomSheet.tsx
index 5034f236a..654ac5207 100644
--- a/src/solana/WalletSignBottomSheet.tsx
+++ b/src/features/solana/WalletSignBottomSheet.tsx
@@ -5,25 +5,28 @@ import {
BottomSheetModalProvider,
BottomSheetScrollView,
} from '@gorhom/bottom-sheet'
-import { useColors, useOpacity } from '@theme/themeHooks'
+import { useBorderRadii } from '@config/theme/themeHooks'
import React, {
Ref,
forwardRef,
memo,
useCallback,
useImperativeHandle,
+ useMemo,
useRef,
useState,
} from 'react'
-import { useSharedValue } from 'react-native-reanimated'
-import { WalletSignBottomSheetSimulated } from './WalletSIgnBottomSheetSimulated'
-import { WalletSignBottomSheetCompact } from './WalletSignBottomSheetCompact'
+import { ThemeProvider } from '@shopify/restyle'
+import { darkTheme } from '@config/theme/theme'
+import { StyleProp, ViewStyle } from 'react-native'
import {
WalletSignBottomSheetProps,
WalletSignBottomSheetRef,
WalletSignOpts,
WalletStandardMessageTypes,
} from './walletSignBottomSheetTypes'
+import { WalletSignBottomSheetCompact } from './WalletSignBottomSheetCompact'
+import { WalletSignBottomSheetSimulated } from './WalletSIgnBottomSheetSimulated'
const WalletSignBottomSheet = forwardRef(
(
@@ -34,10 +37,7 @@ const WalletSignBottomSheet = forwardRef(
((value: boolean | PromiseLike) => void) | null
>(null)
useImperativeHandle(ref, () => ({ show, hide }))
- const { secondaryText } = useColors()
- const { backgroundStyle } = useOpacity('surfaceSecondary', 1)
- const animatedContentHeight = useSharedValue(0)
-
+ const borderRadii = useBorderRadii()
const bottomSheetModalRef = useRef(null)
const [simulated, setSimulated] = useState(false)
const [walletSignOpts, setWalletSignOpts] = useState({
@@ -101,17 +101,41 @@ const WalletSignBottomSheet = forwardRef(
}
}, [hide, promiseResolve])
+ const handleIndicatorStyle = useMemo(() => {
+ return {
+ width: 90,
+ height: 4,
+ backgroundColor: darkTheme.colors.secondaryText,
+ }
+ }, [])
+
+ const handleStyle = useMemo(
+ () =>
+ ({
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ backgroundColor: 'transparent',
+ } as StyleProp),
+ [],
+ )
+
return (
-
- {hasRenderer && !simulated ? (
- setSimulated(true)}
- onAccept={onAcceptHandler}
- onCancel={onCancelHandler}
- />
- ) : (
-
- )}
-
+
+
+ {hasRenderer && !simulated ? (
+ setSimulated(true)}
+ onAccept={onAcceptHandler}
+ onCancel={onCancelHandler}
+ />
+ ) : (
+
+ )}
+
+
{children}
@@ -146,4 +171,17 @@ const WalletSignBottomSheet = forwardRef(
},
)
-export default memo(WalletSignBottomSheet)
+const WalletSignBottomSheetWrapper = forwardRef(
+ (
+ { onClose, children }: WalletSignBottomSheetProps,
+ ref: Ref,
+ ) => {
+ return (
+
+ {children}
+
+ )
+ },
+)
+
+export default memo(WalletSignBottomSheetWrapper)
diff --git a/src/solana/WalletSignBottomSheetCompact.tsx b/src/features/solana/WalletSignBottomSheetCompact.tsx
similarity index 77%
rename from src/solana/WalletSignBottomSheetCompact.tsx
rename to src/features/solana/WalletSignBottomSheetCompact.tsx
index 7e775c363..feb500e9b 100644
--- a/src/solana/WalletSignBottomSheetCompact.tsx
+++ b/src/features/solana/WalletSignBottomSheetCompact.tsx
@@ -65,38 +65,40 @@ export const WalletSignBottomSheetCompact = ({
)
return (
-
+
{warning && (
-
+
{warning}
)}
{!(insufficientFunds || insufficientRentExempt) && (
- {header || t('transactions.signTxn')}
+
+ {header || t('transactions.signTxn')}
+
)}
{!(insufficientFunds || insufficientRentExempt) && message && (
-
+
{message}
)}
{(insufficientFunds || insufficientRentExempt) && (
-
+
{insufficientFunds
? t('browserScreen.insufficientFunds')
: t('browserScreen.insufficientRentExempt', {
@@ -106,17 +108,19 @@ export const WalletSignBottomSheetCompact = ({
)}
{renderer && renderer()}
-
+
- {t('browserScreen.totalNetworkFee')}
+
+ {t('browserScreen.totalNetworkFee')}
+
-
+
{`~${estimatedTotalSolByLamports} SOL`}
-
+
-
+
{t('transactions.simulateTxn')}
@@ -124,25 +128,25 @@ export const WalletSignBottomSheetCompact = ({
diff --git a/src/solana/WalletSignBottomSheetTransaction.tsx b/src/features/solana/WalletSignBottomSheetTransaction.tsx
similarity index 81%
rename from src/solana/WalletSignBottomSheetTransaction.tsx
rename to src/features/solana/WalletSignBottomSheetTransaction.tsx
index ea1189709..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'
@@ -120,13 +120,13 @@ const WalletSignBottomSheetTransaction = ({
}, [transaction.writableAccounts, warningsByAccount, wallet])
return (
-
+
-
+
{uncollapsedAccounts.length + collapsedAccounts.length}
- {t('browserScreen.accounts')}
+
+ {' '}
+ {t('browserScreen.accounts')}
+
{nonAccountWarnings.length > 0 ? (
-
-
+
+
-
+
{nonAccountWarnings.length === 1
? nonAccountWarnings[0].shortMessage
: `${nonAccountWarnings.length} Warnings`}
@@ -156,14 +159,21 @@ const WalletSignBottomSheetTransaction = ({
) : null}
- {transactionIdx + 1}
- {t('generic.of')}
- {totalTransactions}
+
+ {transactionIdx + 1}
+
+
+ {' '}
+ {t('generic.of')}{' '}
+
+
+ {totalTransactions}
+
Linking.openURL(transaction.explorerLink)}
>
@@ -173,7 +183,7 @@ const WalletSignBottomSheetTransaction = ({
{!transaction.error &&
nonAccountWarnings.length > 0 &&
!errorsCollapsed ? (
-
+
{nonAccountWarnings.map((warning, idx) => (
{transaction.error ? (
) : (
{uncollapsedAccounts.map((writableAccount) => (
setExpanded(!expanded)}>
-
+
-
+
{collapsedAccounts.length} {t('browserScreen.accounts')}
@@ -262,7 +276,7 @@ const WalletSignBottomSheetTransaction = ({
-
+
@@ -286,9 +300,9 @@ const WalletSignBottomSheetTransaction = ({
>
) : null}
{transaction.possibleCNftChanges.slice(0, 10).map((asset) => (
-
+
-
+
{asset.content.metadata?.name || 'Unknown cNFT'}
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 61%
rename from src/solana/WarningBox.tsx
rename to src/features/solana/WarningBox.tsx
index dc04f6a05..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,
@@ -12,22 +12,22 @@ export const WarningBox = ({
}) => {
return (
-
+
-
+
{header}
-
+
{body}
diff --git a/src/solana/WritableAccountPreview.tsx b/src/features/solana/WritableAccountPreview.tsx
similarity index 77%
rename from src/solana/WritableAccountPreview.tsx
rename to src/features/solana/WritableAccountPreview.tsx
index c04ba4649..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 {
@@ -104,7 +104,7 @@ export const WritableAccountPreview = ({
)
: diff(writableAccount.pre.account, writableAccount.post.account)
return (
-
+
{warnings.map((warning, idx) => (
-
+
{t('browserScreen.estimatedAccountChanges')}
-
+
{writableAccount.pre.account && !writableAccount.post.account && (
-
+
{t('browserScreen.accountDeleted')}
)}
{!writableAccount.pre.account && writableAccount.post.account && (
-
+
{t('browserScreen.accountCreated')}
)}
@@ -155,7 +155,7 @@ export const WritableAccountPreview = ({
justifyContent="flex-start"
overflow="hidden"
>
-
+
{d.field}
{d.preValue || 'null'}
-
+
{d.postValue || 'null'}
@@ -184,27 +184,27 @@ export const WritableAccountPreview = ({
-
+
{t('browserScreen.instructionsAndPrograms')}
-
+
{instructions.map(({ parsed, raw }, index) => (
-
+
{parsed?.name || t('generic.unknown')}
-
+
{shortenAddress(raw.programId.toBase58())} (
{parsed?.programName})
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 2b719cc47..481296fc7 100644
--- a/src/features/swaps/SwapItem.tsx
+++ b/src/features/swaps/SwapItem.tsx
@@ -4,11 +4,11 @@ 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, StyleSheet } from 'react-native'
+import { GestureResponderEvent, Pressable } from 'react-native'
export type SwapItemProps = {
isPaying: boolean
@@ -38,9 +38,9 @@ const SwapItem = ({
const getBackgroundColorStyle = useCallback(
(pressed: boolean) => {
if (pressed) {
- return generateBackgroundStyle('black500', 1.0)
+ return generateBackgroundStyle('cardBackground', 0.7)
}
- return generateBackgroundStyle('surfaceSecondary', 1.0)
+ return generateBackgroundStyle('cardBackground', 1.0)
},
[generateBackgroundStyle],
)
@@ -49,50 +49,45 @@ const SwapItem = ({
{({ pressed }) => (
-
-
+
+
-
- {isPaying ? t('swapsScreen.youPay') : t('swapsScreen.youReceive')}
-
-
-
- {!loading ? amount.toString() : t('generic.loading')}
+
+
+ {isPaying
+ ? t('swapsScreen.youPay')
+ : t('swapsScreen.youReceive')}
- {`${symbol}`}
+
+
+ {!loading ? amount.toString() : t('generic.loading')}
+
+ {`${symbol}`}
+
- {isPaying && (
-
- )}
)}
)
}
-const styles = StyleSheet.create({
- rotatedBox: {
- height: 18,
- width: 18,
- margin: -9,
- transform: [{ rotate: '45deg' }],
- },
-})
-
export default memo(SwapItem)
diff --git a/src/features/swaps/SwapNavigator.tsx b/src/features/swaps/SwapNavigator.tsx
index 52444c665..219a8f35e 100644
--- a/src/features/swaps/SwapNavigator.tsx
+++ b/src/features/swaps/SwapNavigator.tsx
@@ -2,19 +2,22 @@ import {
createNativeStackNavigator,
NativeStackNavigationOptions,
} from '@react-navigation/native-stack'
-import { JupiterProvider } from '@storage/JupiterProvider'
-import React, { memo } from 'react'
+import { JupiterProvider } from '@config/storage/JupiterProvider'
+import React, { memo, useMemo } from 'react'
import SwappingScreen from './SwappingScreen'
import SwapScreen from './SwapScreen'
const SwapStack = createNativeStackNavigator()
-const cardPresentation: NativeStackNavigationOptions = {
- headerShown: false,
- presentation: 'card',
-}
-
const SwapStackScreen = () => {
+ const cardPresentation: NativeStackNavigationOptions = useMemo(
+ () => ({
+ headerShown: false,
+ presentation: 'card',
+ }),
+ [],
+ )
+
return (
diff --git a/src/features/swaps/SwapScreen.tsx b/src/features/swaps/SwapScreen.tsx
index dee182657..38c38de8c 100644
--- a/src/features/swaps/SwapScreen.tsx
+++ b/src/features/swaps/SwapScreen.tsx
@@ -1,10 +1,9 @@
-import Menu from '@assets/images/menu.svg'
-import Plus from '@assets/images/plus.svg'
-import Refresh from '@assets/images/refresh.svg'
+import Menu from '@assets/svgs/menu.svg'
+import Plus from '@assets/svgs/plus.svg'
import AddressBookSelector, {
AddressBookRef,
} from '@components/AddressBookSelector'
-import { ReAnimatedBlurBox, ReAnimatedBox } from '@components/AnimatedBox'
+import { ReAnimatedBox } from '@components/AnimatedBox'
import Box from '@components/Box'
import ButtonPressable from '@components/ButtonPressable'
import CircleLoader from '@components/CircleLoader'
@@ -38,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 } 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 {
@@ -66,9 +65,15 @@ import {
KeyboardAvoidingView,
TouchableWithoutFeedback,
Keyboard,
+ Image,
} from 'react-native'
-import { Edge } from 'react-native-safe-area-context'
-import { useSolana } from '../../solana/SolanaProvider'
+import { Edge, useSafeAreaInsets } from 'react-native-safe-area-context'
+import { NavBarHeight } from '@components/ServiceNavBar'
+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 '@features/solana/SolanaProvider'
import { solAddressIsValid } from '../../utils/accountUtils'
import SwapItem from './SwapItem'
import { SwapNavigationProp } from './swapTypes'
@@ -83,6 +88,8 @@ enum SelectorMode {
const SwapScreen = () => {
const { t } = useTranslation()
+ const { bottom } = useSafeAreaInsets()
+ const spacing = useSpacing()
const { currentAccount } = useAccountStorage()
const { isDevnet, anchorProvider, connection } = useSolana()
const wallet = useCurrentWallet()
@@ -158,7 +165,7 @@ const SwapScreen = () => {
},
[],
)
- const hitSlop = useHitSlop('l')
+ const hitSlop = useHitSlop('6')
const handleEditAddress = useCallback((text?: string) => {
setRecipient(text || '')
@@ -178,8 +185,8 @@ const SwapScreen = () => {
return t('swapsScreen.insufficientTokensToSwap')
if (hasInsufficientBalance) return t('generic.insufficientBalance')
if (networkError) return networkError
- if (transactionError) return transactionError
if (jupiterError) return jupiterError
+ if (transactionError) return transactionError
if (routeNotFound) return t('swapsScreen.routeNotFound')
}, [
hasRecipientError,
@@ -236,10 +243,6 @@ const SwapScreen = () => {
outputMint,
])
- const handleClose = useCallback(() => {
- navigation.goBack()
- }, [navigation])
-
useAsync(async () => {
refresh()
}, [])
@@ -260,101 +263,33 @@ const SwapScreen = () => {
const Header = useMemo(() => {
return (
-
-
+
+
+
+
{t('swapsScreen.title')}
-
-
-
-
- )
- }, [refresh, t, handleClose])
-
- const Slippage = useMemo(() => {
- if (isDevnet)
- return (
-
- )
-
- const bpsOptions: number[] = [30, 50, 100]
- const disabled = outputMint.equals(DC_MINT)
-
- return (
-
- setSlippageInfoVisible(true)}
+ textAlign="center"
>
-
- {t('swapsScreen.slippage')}
-
-
-
- {bpsOptions.map((bps, idx) => {
- const isLast = idx === bpsOptions.length - 1
- const isActive = slippageBps === bps
-
- return (
- setSlippageBps(bps)}
- >
-
- {bps / 100}%
-
-
- )
- })}
+ {t('swapsScreen.subtitle')}
+
)
- }, [
- slippageBps,
- setSlippageBps,
- outputMint,
- setSlippageInfoVisible,
- t,
- isDevnet,
- ])
+ }, [refresh, t])
const setTokenTypeHandler = useCallback(
(mint: PublicKey) => {
@@ -478,19 +413,30 @@ const SwapScreen = () => {
],
)
+ useEffect(() => {
+ setRecipient('')
+ setRecipientOpen(false)
+ setOutputAmount(0)
+ }, [
+ inputMint,
+ inputAmount,
+ outputMint,
+ setRecipient,
+ setRecipientOpen,
+ setOutputAmount,
+ ])
+
useEffect(() => {
// if changing outputMint ensure we get new routes
;(async () => {
if (
!isDevnet &&
- inputMintAcc &&
- outputMintAcc &&
+ inputMintAcc?.address === inputMint &&
+ outputMintAcc?.address === outputMint &&
typeof inputAmount !== 'undefined' &&
inputAmount > 0 &&
!outputMintAcc?.address.equals(DC_MINT)
) {
- setRecipient('')
- setRecipientOpen(false)
await getOutputAmount({
balance: toBN(inputAmount || 0, inputMintAcc.decimals),
})
@@ -498,12 +444,12 @@ const SwapScreen = () => {
})()
}, [
getOutputAmount,
+ inputMint,
inputAmount,
inputMintAcc,
+ outputMint,
outputMintAcc,
isDevnet,
- setRecipient,
- setRecipientOpen,
])
const getInputAmount = useCallback(
@@ -671,248 +617,321 @@ const SwapScreen = () => {
return loadingPrice
}, [loading, loadingPrice, isDevnet])
- return (
-
- [30, 50, 100], [])
+
+ const options = useMemo(
+ () =>
+ bpsOptions.map((bps, idx) => {
+ return {
+ value: idx,
+ label: `${bps / 100}%`,
+ }
+ }),
+ [bpsOptions],
+ )
+
+ const onItemSelected = useCallback(
+ (index: number) => {
+ const bps = bpsOptions[index]
+ setSlippageBps(bps)
+ },
+ [bpsOptions],
+ )
+
+ const onToggleSlippageInfo = useCallback(() => {
+ setSlippageInfoVisible(!slippageInfoVisible)
+ changeNavigationBarColor(
+ slippageInfoVisible ? colors.primaryBackground : colors.primaryText,
+ )
+ }, [colors, slippageInfoVisible])
+
+ const Slippage = useMemo(() => {
+ if (isDevnet) {
+ return null
+ }
+
+ const disabled = outputMint.equals(DC_MINT)
+
+ if (disabled) {
+ return null
+ }
+
+ return (
+
-
+
+ {t('swapsScreen.slippage')}
+
+
+
+ What is slippage?
+
+
+
+
+
+ )
+ }, [isDevnet, outputMint, t, onToggleSlippageInfo, options, onItemSelected])
+
+ return (
+
+
+
-
-
-
-
- {Header}
-
-
- {Slippage}
-
-
- {!isRecipientOpen && outputMint.equals(DC_MINT) && (
-
-
-
- {t('swapsScreen.addRecipient')}
-
-
-
-
- )}
- {isRecipientOpen && (
-
- )}
- {showError && (
-
-
- {showError}
-
-
- )}
- {priceImpact > 2.5 && (
-
-
- {t('swapsScreen.priceImpact', {
- percent: priceImpact.toFixed(2),
- })}
-
-
- )}
+
+ {Header}
+
+
+ {Slippage}
+
+
+ {!isRecipientOpen && outputMint.equals(DC_MINT) && (
+
+
+
+ {t('swapsScreen.addRecipient')}
+
+
-
-
-
-
- ) : undefined
- }
+
+ )}
+ {isRecipientOpen && (
+
-
-
- {!isDevnet && !outputMint.equals(DC_MINT) && (
-
- )}
-
+
- {!isDevnet && !outputMint.equals(DC_MINT) && (
-
- )}
-
-
-
-
-
- {slippageInfoVisible ? (
-
-
-
-
- setSlippageInfoVisible(false)}
- />
+ >
+ {showError}
+
-
+ )}
+ {priceImpact > 2.5 && (
+
- {t('swapsScreen.slippage')}
+ {t('swapsScreen.priceImpact', {
+ percent: priceImpact.toFixed(2),
+ })}
-
+ )}
+
+
+
+
+
+ ) : undefined
+ }
+ />
+
+
+ {!isDevnet && !outputMint.equals(DC_MINT) && (
+
+ )}
+
+ {!isDevnet && !outputMint.equals(DC_MINT) && (
+
+ )}
+
+
+
+
+ {slippageInfoVisible ? (
+
+
+
+
+
+
-
+
- {t('swapsScreen.slippageInfo')}
+ {t('swapsScreen.slippage')}
+
-
- ) : undefined}
-
-
-
+
+
+ {t('swapsScreen.slippageInfo')}
+
+
+
+
+
+ ) : undefined}
+
+
+
+
)
}
diff --git a/src/features/swaps/SwappingScreen.tsx b/src/features/swaps/SwappingScreen.tsx
index 0677c2fef..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'
@@ -51,19 +51,19 @@ const SwappingScreen = () => {
return (
-
+
@@ -78,12 +78,12 @@ const SwappingScreen = () => {
backgroundColor="secondaryBackground"
>
{TokensSwappedContainer}
@@ -93,13 +93,17 @@ const SwappingScreen = () => {
entering={FadeIn}
exiting={FadeOut}
>
-
+
{t('swapsScreen.swapComplete')}
{t('swapsScreen.swapCompleteBody')}
@@ -114,17 +118,17 @@ const SwappingScreen = () => {
exiting={FadeOut}
>
{t('swapsScreen.swapError')}
{parseTransactionError(
@@ -142,9 +146,9 @@ const SwappingScreen = () => {
exiting={FadeOut}
>
{t('swapsScreen.swapError')}
@@ -159,42 +163,42 @@ const SwappingScreen = () => {
exiting={FadeOut}
>
{t('swapsScreen.swappingTokens')}
{t('swapsScreen.swappingTokensBody')}
-
-
+
+
)}
-
+
+
}
/>
diff --git a/src/features/txnDelegation/LinkWallet.tsx b/src/features/txnDelegation/LinkWallet.tsx
index 7e8553bb8..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 { HomeNavigationProp } from '../home/homeTypes'
-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
@@ -33,7 +30,7 @@ const LinkWallet = () => {
const {
params: { requestAppId, callbackUrl, appName },
} = useRoute()
- const navigation = useNavigation()
+ const navigation = useNavigation()
const rootNav = useNavigation()
const { t } = useTranslation()
const accountSelectorRef = useRef(null)
@@ -63,7 +60,7 @@ const LinkWallet = () => {
} else {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
}
},
@@ -140,37 +137,33 @@ const LinkWallet = () => {
-
+
{t('linkWallet.title', { appName })}
-
+
{t('linkWallet.body', { appName })}
-
+
{t('linkWallet.yes')}
@@ -178,12 +171,12 @@ const LinkWallet = () => {
-
+
{t('linkWallet.no')}
diff --git a/src/features/txnDelegation/SignHotspot.tsx b/src/features/txnDelegation/SignHotspot.tsx
index ab11961aa..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,15 +23,12 @@ 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 {
- 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 { HomeNavigationProp } from '../home/homeTypes'
import useSolTxns from './useSolTxns'
const onboardingClient = new OnboardingClient(`${Config.ONBOARDING_API_URL}/v3`)
@@ -49,12 +46,12 @@ const SignHotspot = () => {
configMsgStr: params.configurationMessage,
})
- const navigation = useNavigation()
+ const navigation = useNavigation()
const rootNav = useNavigation()
const { t } = useTranslation()
const [validated, setValidated] = useState()
const { accounts } = useAccountStorage()
- const { surfaceContrastText } = useColors()
+ const { secondaryText } = useColors()
const linkInvalid = useMemo(() => {
return (
@@ -86,7 +83,7 @@ const SignHotspot = () => {
} else {
rootNav.reset({
index: 0,
- routes: [{ name: 'TabBarNavigator' }],
+ routes: [{ name: 'ServiceSheetNavigator' }],
})
}
},
@@ -222,12 +219,12 @@ const SignHotspot = () => {
if (linkInvalid) {
return (
-
+
-
+
{t('signHotspot.error.title')}
-
+
{t('signHotspot.error.subtitle', {
maker: parsedToken?.appName || 'Maker',
})}
@@ -238,10 +235,10 @@ const SignHotspot = () => {
-
+
{t('signHotspot.error.takeMeBack', {
maker: parsedToken?.appName || 'Maker',
})}
@@ -257,12 +254,12 @@ const SignHotspot = () => {
{title ? (
{
)}
-
+
{t('signHotspot.name')}
-
+
{name}
{locationData?.location && (
<>
-
+
{t('signHotspot.location')}
-
+
{locationData.location}
>
)}
{solana.configMsg && (
<>
-
+
{t('signHotspot.direction')}
-
+
{`${(
METERS_TO_FEET * solana.configMsg.height
).toLocaleString()}ft/${solana.configMsg.azimuth}° ${degToCompass(
@@ -322,29 +311,21 @@ const SignHotspot = () => {
)}
{locationData?.gain !== undefined && (
-
-
+
+
{t('generic.gain')}:
-
+
{locationData.gain}
)}
{locationData?.elevation !== undefined && (
-
+
{t('generic.elevation')}:
-
+
{locationData.elevation}
@@ -353,26 +334,18 @@ const SignHotspot = () => {
{(solana.burnAmounts?.hntFee?.gt(new BN(0)) ||
solana.burnAmounts?.dcFee?.gt(new BN(0))) && (
<>
-
+
{t('signHotspot.burnAmounts')}
{solana.burnAmounts?.dcFee?.gt(new BN(0)) && (
-
+
{solana.burnAmounts?.dcFee?.toString()}
)}
{solana.burnAmounts?.hntFee?.gt(new BN(0)) && (
-
+
{solana.burnAmounts?.hntFee?.toString()}
)}
@@ -380,30 +353,26 @@ const SignHotspot = () => {
)}
{transferData?.newOwner && (
<>
-
+
{t('signHotspot.newOwner')}
-
+
{transferData.newOwner}
>
)}
{!!parsedToken?.address && accounts?.[parsedToken.address] && (
<>
-
+
{t('signHotspot.owner')}
-
+
{formatAccountAlias(accounts[parsedToken.address])}
@@ -412,51 +381,47 @@ const SignHotspot = () => {
)}
{!!gatewayAddress && (
<>
-
+
{t('generic.maker')}:
-
+
{onboardingRecord?.maker.name || 'Unknown'}
>
)}
-
+
-
+
{t('generic.cancel')}
-
+
{t('generic.confirm')}
{submitLoading && (
-
-
+
+
)}
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 76%
rename from src/features/account/AccountActionBar.tsx
rename to src/features/wallet/AccountActionBar.tsx
index c3d9c50a5..43d43fb31 100644
--- a/src/features/account/AccountActionBar.tsx
+++ b/src/features/wallet/AccountActionBar.tsx
@@ -6,8 +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 { useAppStorage } from '../../storage/AppStorageProvider'
-import { HomeNavigationProp } from '../home/homeTypes'
+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'
@@ -44,64 +45,63 @@ const AccountActionBar = ({
hasAirdrop,
mint,
}: Props) => {
- const navigation = useNavigation()
+ const navigation = useNavigation()
+ const walletPageNav = useNavigation()
const { t } = useTranslation()
const { requirePinForPayment, pin } = useAppStorage()
const handleAction = useCallback(
(type: Action) => () => {
switch (type) {
+ default:
case 'send': {
if (
(pin?.status === 'on' || pin?.status === 'restored') &&
requirePinForPayment
) {
- navigation.navigate('ConfirmPin', { action: 'payment' })
+ walletPageNav.navigate('ConfirmPin', { action: 'payment' })
} else {
- navigation.navigate('PaymentScreen', {
- mint: mint?.toBase58(),
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ navigation.navigate('Send', {
+ screen: 'PaymentScreen',
+ params: {
+ mint: mint?.toBase58(),
+ },
})
}
break
}
case 'request': {
- navigation.navigate('RequestScreen')
+ navigation.navigate('Receive')
break
}
case 'swaps': {
- navigation.navigate('SwapNavigator')
+ navigation.navigate('Swap')
break
}
case 'airdrop': {
if (mint) {
- navigation.navigate('AirdropScreen', { mint: mint?.toBase58() })
+ walletPageNav.navigate('AirdropScreen', { mint: mint?.toBase58() })
}
break
}
- case '5G': {
- navigation.navigate('OnboardData')
- break
- }
case 'delegate': {
- navigation.navigate('BurnScreen', {
+ walletPageNav.navigate('BurnScreen', {
address: '',
amount: '',
isDelegate: true,
})
break
}
- default: {
- // show()
- break
- }
}
},
- [pin?.status, requirePinForPayment, navigation, mint],
+ [pin?.status, requirePinForPayment, navigation, mint, walletPageNav],
)
const fabMargin = useMemo(() => {
- if (compact) return 'm'
- if (maxCompact) return 's'
+ if (compact) return '4'
+ if (maxCompact) return '2'
return undefined
}, [compact, maxCompact])
@@ -121,10 +121,9 @@ const AccountActionBar = ({
>
{hasBottomTitle && (
-
+
{hasBottomTitle && (
-
+
{hasBottomTitle && (
-
+
{hasBottomTitle && (
-
+
void
-}) => {
+} & BoxProps) => {
const mint = usePublicKey(token)
const wallet = useCurrentWallet()
const { amount, decimals } = useOwnedAmount(wallet, mint)
@@ -55,24 +54,27 @@ const CheckableTokenListItem = ({
return (
{}}
flexDirection="row"
minHeight={72}
alignItems="center"
- paddingHorizontal="m"
- paddingVertical="m"
+ padding="4"
borderBottomColor="primaryBackground"
- borderBottomWidth={bottomBorder ? 0 : 1}
+ borderBottomWidth={bottomBorder ? 2 : 0}
disabled
+ {...rest}
>
-
+
-
+
{`${balanceToDisplay} `}
@@ -81,7 +83,7 @@ const CheckableTokenListItem = ({
{symbol && (
@@ -93,11 +95,11 @@ const CheckableTokenListItem = ({
style={{ height: 18, width: 18 }}
tintColors={{
true: colors.primaryText,
- false: colors.transparent10,
+ false: colors.primaryText,
}}
- onCheckColor={colors.secondary}
+ onCheckColor={colors.primaryBackground}
onTintColor={colors.primaryText}
- tintColor={colors.transparent10}
+ tintColor={colors.primaryText}
onFillColor={colors.primaryText}
onAnimationType="fill"
offAnimationType="fill"
@@ -110,9 +112,6 @@ const CheckableTokenListItem = ({
}
const AccountManageTokenListScreen: React.FC = () => {
- const navigation = useNavigation()
- const { primaryText } = useColors()
- const hitSlop = useHitSlop('l')
const { visibleTokens, setVisibleTokens } = useVisibleTokens()
const { tokenAccounts } = useBalance()
const mints = useMemo(() => {
@@ -141,12 +140,23 @@ const AccountManageTokenListScreen: React.FC = () => {
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ index, item: token }: { index: number; item: string }) => {
+ const isFirst = index === 0
+ const isLast = index === (mints?.length || 0) - 1
+ const borderTopStartRadius = isFirst ? 'xl' : 'none'
+ const borderTopEndRadius = isFirst ? 'xl' : 'none'
+ const borderBottomStartRadius = isLast ? 'xl' : 'none'
+ const borderBottomEndRadius = isLast ? 'xl' : 'none'
+
return (
)
},
@@ -156,44 +166,30 @@ const AccountManageTokenListScreen: React.FC = () => {
const keyExtractor = useCallback((item: string) => {
return item
}, [])
- const safeEdges = useMemo(() => ['top'] as Edge[], [])
return (
-
-
-
-
-
-
-
-
-
-
- }
- data={mints}
- renderItem={renderItem}
- keyExtractor={keyExtractor}
- />
-
+
+ }
+ >
+
+
+
+
)
}
diff --git a/src/features/account/AccountTokenBalance.tsx b/src/features/wallet/AccountTokenBalance.tsx
similarity index 85%
rename from src/features/account/AccountTokenBalance.tsx
rename to src/features/wallet/AccountTokenBalance.tsx
index 0ba6ab27f..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 { 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'
@@ -17,7 +17,7 @@ import { useTranslation } from 'react-i18next'
type Props = {
mint: PublicKey
- textVariant?: 'h0' | 'h1' | 'h2' | 'h2Medium'
+ textVariant?: TextVariant
showTicker?: boolean
} & BoxProps
@@ -38,7 +38,7 @@ const EscrowDetails = () => {
return (
-
+
{t('accountsScreen.receivedBalance', {
amount: humanReadable(
new BN(iotEscrowAcct?.amount?.toString() || '0').add(
@@ -64,6 +64,7 @@ const AccountTokenBalance = ({
decimals,
loading: loadingOwned,
} = useOwnedAmount(wallet, mint)
+
const balanceStr =
typeof decimals !== 'undefined' && balance
? humanReadable(new BN(balance?.toString() || '0'), decimals)
@@ -80,10 +81,15 @@ const AccountTokenBalance = ({
{!showTicker &&
(loadingOwned ? (
-
+
) : (
{showTicker && (
{
return (
{balanceString || ' '}
diff --git a/src/features/wallet/AccountTokenScreen.tsx b/src/features/wallet/AccountTokenScreen.tsx
new file mode 100644
index 000000000..cfa6c51c5
--- /dev/null
+++ b/src/features/wallet/AccountTokenScreen.tsx
@@ -0,0 +1,324 @@
+import ActivityIndicator from '@components/ActivityIndicator'
+import { ReAnimatedBox } from '@components/AnimatedBox'
+import BackScreen from '@components/BackScreen'
+import Box from '@components/Box'
+import FadeInOut, { DelayedFadeIn } from '@components/FadeInOut'
+import Text from '@components/Text'
+import TokenIcon from '@components/TokenIcon'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { useOwnedAmount } from '@helium/helium-react-hooks'
+import { DC_MINT, HNT_MINT, IOT_MINT, MOBILE_MINT } from '@helium/spl-utils'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+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 '@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 { PublicKey } from '@solana/web3.js'
+import ScrollBox from '@components/ScrollBox'
+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'
+import AccountTokenBalance from './AccountTokenBalance'
+import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
+import TransactionDetailSelector, {
+ TransactionDetailSelectorRef,
+} from './TransactionDetail'
+import TxnListItem from './TxnListItem'
+import useSolanaActivityList from './useSolanaActivityList'
+import { TokenListGovItem } from './TokenListItem'
+
+const MIN_BOTTOM_BAR_HEIGHT = 80
+
+type Route = RouteProp
+
+const AccountTokenScreen = () => {
+ const { t } = useTranslation()
+ const route = useRoute()
+ const mintStr = useMemo(() => route.params.mint, [route.params.mint])
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const mint = usePublicKey(mintStr)!
+ const wallet = useCurrentWallet()
+ const { amount } = useOwnedAmount(wallet, mint)
+ const { currentAccount } = useAccountStorage()
+ const headerContainerRef = useRef(null)
+ const { cluster, isDevnet } = useSolana()
+ const colors = useColors()
+ const { showModal } = useModal()
+ const [
+ onEndReachedCalledDuringMomentum,
+ setOnEndReachedCalledDuringMomentum,
+ ] = useState(true)
+ const transactionDetailsRef = useRef(null)
+
+ const { json, symbol } = useMetaplexMetadata(mint)
+
+ const listStyle = useMemo(() => {
+ return {
+ backgroundColor: colors.primaryBackground,
+ marginBottom: 100,
+ }
+ }, [colors])
+
+ const filterState = useActivityFilter()
+
+ const {
+ data: activityData,
+ requestMore: fetchMoreActivity,
+ loading: activityLoading,
+ now,
+ } = useSolanaActivityList({
+ account: currentAccount,
+ filter: filterState.filter,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ mint: mint!,
+ })
+
+ const handleOnFetchMoreActivity = useCallback(() => {
+ if (activityLoading || onEndReachedCalledDuringMomentum) return
+
+ fetchMoreActivity()
+ setOnEndReachedCalledDuringMomentum(true)
+ }, [activityLoading, fetchMoreActivity, onEndReachedCalledDuringMomentum])
+
+ const handleOnMomentumScrollBegin = useCallback(() => {
+ setOnEndReachedCalledDuringMomentum(false)
+ }, [])
+
+ const showTransactionDetail = useCallback(
+ (item: Activity) => {
+ transactionDetailsRef?.current?.showTransaction({
+ item,
+ accountAddress: currentAccount?.address || '',
+ mint,
+ })
+ },
+ [currentAccount?.address, transactionDetailsRef, mint],
+ )
+
+ const hasAirdrop = useMemo(() => {
+ if (cluster === 'devnet') {
+ return (
+ mint.equals(NATIVE_MINT) ||
+ mint.equals(HNT_MINT) ||
+ mint.equals(IOT_MINT) ||
+ mint.equals(MOBILE_MINT)
+ )
+ }
+ return false
+ }, [mint, cluster])
+
+ const keyExtractor = useCallback((item: Activity) => {
+ return item.hash
+ }, [])
+
+ const renderItem = useCallback(
+ ({ item, index }) => {
+ const isFirst = index === 0
+ const isLast = index === (activityData?.length || 0) - 1
+ const borderTopStartRadius = isFirst ? 'xl' : 'none'
+ const borderTopEndRadius = isFirst ? 'xl' : 'none'
+ const borderBottomStartRadius = isLast ? 'xl' : 'none'
+ const borderBottomEndRadius = isLast ? 'xl' : 'none'
+ return (
+
+
+
+ )
+ },
+ [activityData?.length, mint, now, showTransactionDetail],
+ )
+
+ const renderFooter = useCallback(() => {
+ if (!activityLoading) {
+ return (
+
+
+ {t('accountsScreen.allFilterFooter')}
+
+
+ )
+ }
+
+ return (
+
+
+
+ )
+ }, [activityLoading, t])
+
+ const actionBarProps = useMemo(() => {
+ let options = {
+ hasSend: true,
+ hasRequest: true,
+ hasDelegate: false,
+ compact: true,
+ hasBottomTitle: true,
+ }
+
+ if (mint.equals(DC_MINT)) {
+ options = {
+ hasSend: false,
+ hasRequest: false,
+ hasDelegate: true,
+ compact: false,
+ hasBottomTitle: false,
+ }
+ }
+
+ return options
+ }, [mint])
+
+ const renderHeader = useCallback(() => {
+ const isGovMint = GovMints.some((m) => new PublicKey(m).equals(mint))
+
+ return (
+
+
+
+
+
+
+
+
+ {!!symbol && (
+
+ )}
+
+
+
+
+ {mint.equals(NATIVE_MINT) &&
+ !isDevnet &&
+ (amount || 0) < MIN_BALANCE_THRESHOLD && (
+ <>
+
+
+ {t('accountsScreen.solWarning')}
+
+
+ showModal({ type: 'InsufficientSolConversion' })
+ }
+ >
+
+ {t('accountsScreen.solSwap')}
+
+
+
+
+ >
+ )}
+
+ {isGovMint && }
+
+ )
+ }, [
+ actionBarProps,
+ hasAirdrop,
+ isDevnet,
+ json?.image,
+ mint,
+ symbol,
+ t,
+ amount,
+ showModal,
+ ])
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+export default AccountTokenScreen
diff --git a/src/features/account/AccountView.tsx b/src/features/wallet/AccountView.tsx
similarity index 92%
rename from src/features/account/AccountView.tsx
rename to src/features/wallet/AccountView.tsx
index 32e758fe6..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'
@@ -59,7 +59,7 @@ const AccountView = ({ selectedBalance, ...boxProps }: Props) => {
{!balanceString && (
{
{balanceString}
@@ -104,7 +104,7 @@ const AccountView = ({ selectedBalance, ...boxProps }: Props) => {
+type Route = RouteProp
const AirdropScreen = () => {
- const navigation = useNavigation()
+ const navigation = useNavigation()
+ const { bottom } = useSafeAreaInsets()
const { currentAccount } = useAccountStorage()
const { anchorProvider } = useSolana()
const { t } = useTranslation()
@@ -47,7 +52,7 @@ const AirdropScreen = () => {
const route = useRoute()
const { mint: mintStr } = route.params
const mint = usePublicKey(mintStr)
- const { symbol, json } = useMetaplexMetadata(mint)
+ const { symbol } = useMetaplexMetadata(mint)
const onAirdrop = useCallback(async () => {
if (!currentAccount?.solanaAddress || !anchorProvider) return
@@ -75,8 +80,6 @@ const AirdropScreen = () => {
}
}, [anchorProvider, currentAccount?.solanaAddress, mint, navigation, symbol])
- const edges = useMemo(() => ['bottom'] as Edge[], [])
-
const onAnimationDropComplete = useCallback(() => {
ring.value = 1
}, [ring])
@@ -146,63 +149,73 @@ const AirdropScreen = () => {
}, [ring, ringDrop])
return (
-
-
-
-
- {t('airdropScreen.title')}
-
+
+
+
+
+
+ {t('airdropScreen.title')}
+
+
+ {t('airdropScreen.subtitle')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- {t('airdropScreen.subtitle')}
+ {errorMessage ? t('airdropScreen.error') : ''}
+
+ }
+ />
-
-
-
-
-
-
-
-
-
-
-
- {errorMessage ? t('airdropScreen.error') : ''}
-
-
- }
- />
-
-
+
+
)
}
diff --git a/src/features/wallet/TokenListItem.tsx b/src/features/wallet/TokenListItem.tsx
new file mode 100644
index 000000000..6a13e0cf6
--- /dev/null
+++ b/src/features/wallet/TokenListItem.tsx
@@ -0,0 +1,513 @@
+/* eslint-disable @typescript-eslint/no-shadow */
+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'
+import TokenIcon from '@components/TokenIcon'
+import TouchableContainer from '@components/TouchableContainer'
+import { useMint, useOwnedAmount } from '@helium/helium-react-hooks'
+import {
+ useHeliumVsrState,
+ usePositions,
+ useRegistrarForMint,
+} from '@helium/voter-stake-registry-hooks'
+import { getPositionKeysForOwner } from '@helium/voter-stake-registry-sdk'
+import { useCurrentWallet } from '@hooks/useCurrentWallet'
+import useHaptic from '@hooks/useHaptic'
+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 '@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 '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 '@config/theme/theme'
+import { useSolana } from '@features/solana/SolanaProvider'
+import AccountTokenCurrencyBalance from './AccountTokenCurrencyBalance'
+
+export const ITEM_HEIGHT = 72
+type Props = {
+ mint: PublicKey
+}
+
+export const TokenSkeleton = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export const TokenListItem = ({ mint }: Props) => {
+ const navigation = useNavigation()
+ const wallet = useCurrentWallet()
+ const {
+ amount,
+ decimals,
+ loading: loadingOwned,
+ } = useOwnedAmount(wallet, mint)
+
+ const { triggerImpact } = useHaptic()
+ const { json, symbol, loading } = useMetaplexMetadata(mint)
+ const mintStr = mint.toBase58()
+
+ const handleNavigation = useCallback(() => {
+ triggerImpact('light')
+ navigation.navigate('AccountTokenScreen', {
+ mint: mintStr,
+ })
+ }, [navigation, mintStr, triggerImpact])
+
+ const balanceToDisplay = useMemo(() => {
+ return amount && typeof decimals !== 'undefined'
+ ? humanReadable(new BN(amount.toString()), decimals)
+ : '0'
+ }, [amount, decimals])
+
+ return (
+
+
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+ {loadingOwned ? (
+
+
+
+
+ ) : (
+
+
+ {json?.name}
+
+
+
+ {`${balanceToDisplay}`}
+
+
+ {symbol}
+
+
+
+ )}
+
+
+ {symbol && (
+
+ )}
+ {/*
+ TODO: Bring this back once we are tracking balances on the wallet api
+ */}
+
+
+
+ )
+}
+
+export const HeliumTokenListItem = ({ mint }: Props) => {
+ const navigation = useNavigation()
+ const wallet = useCurrentWallet()
+ const {
+ amount,
+ decimals,
+ loading: loadingOwned,
+ } = useOwnedAmount(wallet, mint)
+ const { triggerImpact } = useHaptic()
+ const { json, symbol, loading } = useMetaplexMetadata(mint)
+ const mintStr = mint.toBase58()
+ const { amountLocked } = useAmountLocked(mint)
+
+ const handleNavigation = useCallback(() => {
+ triggerImpact('light')
+ navigation.navigate('AccountTokenScreen', {
+ mint: mintStr,
+ })
+ }, [navigation, mintStr, triggerImpact])
+
+ const balanceToDisplay = useMemo(() => {
+ let realAmount = new BN(0)
+ if (amountLocked) {
+ realAmount = realAmount.add(amountLocked)
+ }
+
+ if (amount) {
+ const amountAsBN = new BN(amount.toString())
+ realAmount = realAmount.add(amountAsBN)
+ }
+
+ return realAmount && typeof decimals !== 'undefined'
+ ? humanReadable(realAmount, decimals)
+ : '0'
+ }, [amount, decimals, amountLocked])
+
+ return (
+
+
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+ {loadingOwned ? (
+
+
+
+
+ ) : (
+
+
+ {json?.name}
+
+
+
+ {`${balanceToDisplay}`}
+
+
+ {symbol}
+
+
+
+ )}
+
+
+ {symbol && (
+
+ )}
+ {/*
+ TODO: Bring this back once we are tracking balances on the wallet api
+ */}
+
+
+
+ )
+}
+
+// TODO: Bring back once we add chart history back to the wallet api
+// const PercentChange = ({
+// change,
+// type,
+// }: {
+// change: number
+// type: 'up' | 'down' | 'neutral'
+// }) => {
+// const color = useMemo(() => {
+// switch (type) {
+// case 'up':
+// return 'green.light-500'
+// case 'down':
+// return 'blue.dark-600'
+// case 'neutral':
+// return 'fg.quinary-400'
+// }
+// }, [type])
+
+// const prefix = useMemo(() => {
+// return change > 0 ? '+' : '-'
+// }, [change])
+
+// return (
+//
+// {`${prefix}${change.toFixed(2).toLocaleString()}%`}
+//
+// )
+// }
+
+export const TokenListGovItem = ({
+ mint,
+ ...rest
+}: { mint: PublicKey } & BoxProps) => {
+ const navigation = useNavigation()
+ const { anchorProvider, connection } = useSolana()
+ const wallet = useCurrentWallet()
+ const { triggerImpact } = useHaptic()
+ const { json, symbol, loading } = useMetaplexMetadata(mint)
+ const decimals = useMint(mint)?.info?.decimals
+ const mintStr = mint.toBase58()
+ const colors = useColors()
+ const {
+ positions: contextPositions,
+ mint: govMint,
+ loading: loadingContext,
+ } = useHeliumVsrState()
+ const useContextPositions = useMemo(
+ () => !!govMint?.equals(mint),
+ [govMint, mint],
+ )
+
+ const { registrarKey } = useRegistrarForMint(mint)
+
+ const args = useMemo(
+ () =>
+ wallet &&
+ mint &&
+ connection &&
+ registrarKey && {
+ registrar: registrarKey,
+ owner: wallet,
+ connection,
+ },
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ registrarKey?.toBase58(),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ wallet?.toBase58(),
+ connection,
+ anchorProvider,
+ ],
+ )
+
+ const { result, loading: loadingPositionKeys } = useAsync(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ async (args: any | undefined, useContext: boolean) => {
+ if (args && !useContext) {
+ return getPositionKeysForOwner(args)
+ }
+ },
+ [args, useContextPositions],
+ )
+
+ const { accounts: fetchedPositions, loading: loadingFetchedPositions } =
+ usePositions(result?.positions)
+ const loadingPositions = loadingFetchedPositions || loadingContext
+ const positions = useMemo(
+ () =>
+ useContextPositions
+ ? contextPositions
+ : fetchedPositions?.map((fetched) => fetched.info),
+ [useContextPositions, contextPositions, fetchedPositions],
+ )
+
+ const { amountLocked } = useMemo(() => {
+ if (positions && positions.length) {
+ let amountLocked = new BN(0)
+ positions.forEach((position) => {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ if (position && !position.isProxiedToMe) {
+ amountLocked = amountLocked.add(position.amountDepositedNative)
+ }
+ })
+
+ return {
+ amountLocked,
+ }
+ }
+
+ return {}
+ }, [positions])
+
+ const prevLocked = usePrevious(amountLocked)
+
+ const handleNavigation = useCallback(() => {
+ triggerImpact('light')
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ;(navigation as any).navigate('GovernanceService', {
+ screen: 'PositionsScreen',
+ initial: false,
+ params: { mint: mintStr },
+ })
+ }, [navigation, mintStr, triggerImpact])
+
+ const balanceToDisplay = useMemo(() => {
+ return amountLocked && typeof decimals !== 'undefined'
+ ? humanReadable(new BN(amountLocked.toString()), decimals)
+ : '0'
+ }, [amountLocked, decimals])
+
+ const loadingAmount = useMemo(() => {
+ return !prevLocked && (loadingPositionKeys || loadingPositions)
+ }, [loadingPositionKeys, loadingPositions, prevLocked])
+
+ if (balanceToDisplay === '0') return null
+
+ return (
+
+ {loading ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+ )}
+
+
+ {loadingAmount ? (
+
+
+
+
+ ) : (
+
+
+
+ {`${balanceToDisplay} `}
+
+
+ {symbol} (Locked)
+
+
+
+ )}
+
+
+
+ )
+}
diff --git a/src/features/account/AccountTokenList.tsx b/src/features/wallet/TokensScreen.tsx
similarity index 54%
rename from src/features/account/AccountTokenList.tsx
rename to src/features/wallet/TokensScreen.tsx
index 5524b768e..430d31018 100644
--- a/src/features/account/AccountTokenList.tsx
+++ b/src/features/wallet/TokensScreen.tsx
@@ -1,60 +1,86 @@
-import Config from '@assets/images/config.svg'
-import Text from '@components/Text'
-import TouchableOpacityBox from '@components/TouchableOpacityBox'
-import { BottomSheetFlatList } from '@gorhom/bottom-sheet'
-import { BottomSheetFlatListProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetScrollable/types'
-import { useAccountFetchCache } from '@helium/account-fetch-cache-hooks'
+import Box from '@components/Box'
+import React, { useCallback, useEffect, useMemo } from 'react'
+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 {
- DC_MINT,
- HNT_MINT,
- IOT_MINT,
- MOBILE_MINT,
- truthy,
-} from '@helium/spl-utils'
-import { useNavigation } from '@react-navigation/native'
-import { getAssociatedTokenAddressSync } from '@solana/spl-token'
+ DEFAULT_TOKENS,
+ useVisibleTokens,
+} from '@config/storage/TokensProvider'
import { PublicKey } from '@solana/web3.js'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { DEFAULT_TOKENS, useVisibleTokens } from '@storage/TokensProvider'
-import { useColors } from '@theme/themeHooks'
-import { useBalance } from '@utils/Balance'
+import {
+ HeliumTokenListItem,
+ TokenListItem,
+ TokenSkeleton,
+} from '@features/wallet/TokenListItem'
+import { GovMints } from '@utils/constants'
+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 '@config/storage/AccountStorageProvider'
+import { useAppDispatch } from '@store/store'
+import { syncTokenAccounts } from '@store/slices/balancesSlice'
+import { useAccountFetchCache } from '@helium/account-fetch-cache-hooks'
+import { getAssociatedTokenAddressSync } from '@solana/spl-token'
import { times } from 'lodash'
-import React, { useCallback, useEffect, useMemo } from 'react'
-import { useAsyncCallback } from 'react-async-hook'
+import TouchableOpacityBox from '@components/TouchableOpacityBox'
+import { useNavigation } from '@react-navigation/native'
+import Config from '@assets/svgs/config.svg'
+import Text from '@components/Text'
import { useTranslation } from 'react-i18next'
-import { AppState, RefreshControl } from 'react-native'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
-import Box from '@components/Box'
-import { GovMints } from '../../utils/constants'
-import { useSolana } from '../../solana/SolanaProvider'
-import { syncTokenAccounts } from '../../store/slices/balancesSlice'
-import { useAppDispatch } from '../../store/store'
-import { HomeNavigationProp } from '../home/homeTypes'
-import { TokenListItem, TokenListGovItem, TokenSkeleton } from './TokenListItem'
-
-type Props = {
- onLayout?: BottomSheetFlatListProps['onLayout']
-}
+import { getSortValue } from '@utils/solanaUtils'
+import { checkSecureAccount } from '@config/storage/secureStorage'
+import ScrollBox from '@components/ScrollBox'
+import SharedGroupPreferences from 'react-native-shared-group-preferences'
+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 sortValues: Record = {
- [HNT_MINT.toBase58()]: 10,
- [IOT_MINT.toBase58()]: 9,
- [MOBILE_MINT.toBase58()]: 8,
- [DC_MINT.toBase58()]: 7,
-}
-export function getSortValue(mint: string): number {
- return sortValues[mint] || 0
-}
-
-const AccountTokenList = ({ onLayout }: Props) => {
- const navigation = useNavigation()
- const { t } = useTranslation()
- const { visibleTokens } = useVisibleTokens()
- const { currentAccount } = useAccountStorage()
- const dispatch = useAppDispatch()
+const TokensScreen = () => {
+ const widgetGroup = 'group.com.helium.mobile.wallet.widget'
const { anchorProvider, cluster } = useSolana()
+ const { tokenAccounts } = useBalance()
+ const { visibleTokens } = useVisibleTokens()
const colors = useColors()
+ const spacing = useSpacing()
+ const { bottom } = useSafeAreaInsets()
+ const { currentAccount, sortedAccounts, defaultAccountAddress } =
+ useAccountStorage()
+ const dispatch = useAppDispatch()
+ const { locked, currency } = useAppStorage()
+ const rootNav = useNavigation()
const cache = useAccountFetchCache()
+ const navigation = useNavigation()
+ const serviceNav = useNavigation()
+ const { openedNotification } = useNotificationStorage()
+ const { t } = useTranslation()
+
+ // Hook that is used for helium balance widget.
+ useAsync(async () => {
+ if (Platform.OS === 'ios') {
+ const defaultAccount = sortedAccounts.find(
+ (account: CSAccount) => account.address === defaultAccountAddress,
+ )
+
+ await SharedGroupPreferences.setItem(
+ 'heliumWalletWidgetKey',
+ {
+ defaultAccountAddress: defaultAccount?.solanaAddress,
+ defaultAccountAlias: defaultAccount?.alias,
+ currencyType: currency,
+ cluster,
+ },
+ widgetGroup,
+ )
+ }
+ }, [defaultAccountAddress, sortedAccounts])
const { loading: refetchingTokens, execute: refetchTokens } =
useAsyncCallback(async () => {
@@ -138,11 +164,20 @@ const AccountTokenList = ({ onLayout }: Props) => {
}
}, [refetchTokens])
- const onManageTokenList = useCallback(() => {
- navigation.navigate('AccountManageTokenListScreen')
- }, [navigation])
- const { tokenAccounts } = useBalance()
- const { bottom } = useSafeAreaInsets()
+ // if user signs out from lockscreen
+ useEffect(() => {
+ if (sortedAccounts.length === 0) {
+ rootNav.replace('OnboardingNavigator')
+ }
+ }, [rootNav, sortedAccounts.length])
+
+ useEffect(() => {
+ if (openedNotification && !locked) {
+ // navigate to notifications if we are coming from tapping a push
+ serviceNav.push('NotificationsService')
+ }
+ }, [serviceNav, openedNotification, locked])
+
const mints = useMemo(() => {
const taMints = tokenAccounts
?.filter(
@@ -162,18 +197,44 @@ const AccountTokenList = ({ onLayout }: Props) => {
return all
}, [tokenAccounts, visibleTokens])
- const bottomSpace = useMemo(() => bottom * 2, [bottom])
+ const renderHeader = useCallback(() => {
+ return (
+
+
+
+
+
+
+ )
+ }, [])
+
+ const contentContainerStyle = useMemo(
+ () => ({
+ backgroundColor: colors['base.white'],
+ paddingTop: spacing['4'],
+ paddingBottom: NavBarHeight + bottom,
+ }),
+ [colors, spacing, bottom],
+ )
+
+ useEffect(() => {
+ if (currentAccount?.ledgerDevice) return
+ // if current account is keystone account , check pass
+ if (currentAccount?.keystoneDevice) return
+ const address = currentAccount?.address
+ if (address) checkSecureAccount(address)
+ }, [
+ currentAccount?.address,
+ currentAccount?.ledgerDevice,
+ currentAccount?.keystoneDevice,
+ ])
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ item }: { item: PublicKey }) => {
- if (GovMints.some((m) => new PublicKey(m).equals(item)))
- return (
-
-
-
-
- )
+ if (GovMints.some((m) => new PublicKey(m).equals(item))) {
+ return
+ }
return
},
@@ -190,16 +251,20 @@ const AccountTokenList = ({ onLayout }: Props) => {
)
}, [])
+ const onManageTokenList = useCallback(() => {
+ navigation.navigate('AccountManageTokenListScreen')
+ }, [navigation])
+
const renderFooterComponent = useCallback(() => {
return (
-
+
{t('accountTokenList.manage')}
@@ -208,21 +273,11 @@ const AccountTokenList = ({ onLayout }: Props) => {
const keyExtractor = useCallback((mint: PublicKey) => {
const isGov = GovMints.some((m) => new PublicKey(m).equals(mint))
- return `${mint.toBase58()}${isGov ? '-gov' : ''}`
+ return `${mint.toBase58()}${isGov ? '-gov' : '-spl'}`
}, [])
- const contentContainerStyle = useMemo(
- () => ({
- paddingBottom: bottomSpace,
- }),
- [bottomSpace],
- )
-
return (
- {
tintColor={colors.primaryText}
/>
}
- refreshing={refetchingTokens}
- onRefresh={refetchTokens}
- columnWrapperStyle={{
- flexDirection: 'column',
- }}
- contentContainerStyle={contentContainerStyle}
- renderItem={renderItem}
- ListEmptyComponent={renderEmptyComponent}
- ListFooterComponent={renderFooterComponent}
- keyExtractor={keyExtractor}
- />
+ >
+
+
)
}
-export default AccountTokenList
+export default TokensScreen
diff --git a/src/features/wallet/TokensTabs.tsx b/src/features/wallet/TokensTabs.tsx
new file mode 100644
index 000000000..37109821c
--- /dev/null
+++ b/src/features/wallet/TokensTabs.tsx
@@ -0,0 +1,94 @@
+import SegmentedControl, {
+ SegmentedControlRef,
+} from '@components/SegmentedControl'
+import React, { useCallback, useMemo, useRef } from 'react'
+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 '@config/theme/themeHooks'
+import { useNavigation } from '@react-navigation/native'
+import TokensScreen from './TokensScreen'
+
+export type TokensStackParamList = {
+ TokensScreen: undefined
+ NftList: undefined
+}
+
+export type TokensNavigationProp = StackNavigationProp
+
+const TokensStack = createMaterialTopTabNavigator()
+
+const TokensTabs = () => {
+ const segmentedControlRef = useRef(null)
+ const colors = useColors()
+ const navigatorScreenOptions = useMemo(
+ () =>
+ ({
+ headerShown: false,
+ swipeEnabled: false,
+ } as MaterialTopTabNavigationOptions),
+ [],
+ )
+ const navigation = useNavigation()
+
+ const options = useMemo(
+ () => [
+ {
+ value: 'tokens',
+ label: 'Tokens',
+ Icon: Tokens,
+ },
+ {
+ value: 'collectables',
+ label: 'Collectables',
+ Icon: Collectables,
+ },
+ ],
+ [],
+ )
+
+ const onItemSelected = useCallback(
+ (index: number) => {
+ if (index === 0) {
+ navigation.navigate('TokensScreen')
+ }
+
+ if (index === 1) {
+ navigation.navigate('NftList')
+ }
+ },
+ [navigation],
+ )
+
+ const TopTabs = useCallback(() => {
+ return (
+
+ )
+ }, [onItemSelected, options])
+
+ return (
+
+
+
+
+ )
+}
+
+export default TokensTabs
diff --git a/src/features/wallet/TransactionDetail.tsx b/src/features/wallet/TransactionDetail.tsx
new file mode 100644
index 000000000..e741918ea
--- /dev/null
+++ b/src/features/wallet/TransactionDetail.tsx
@@ -0,0 +1,211 @@
+/* eslint-disable react/no-array-index-key */
+import BlurBox from '@components/BlurBox'
+import HandleBasic from '@components/HandleBasic'
+import SafeAreaBox from '@components/SafeAreaBox'
+import {
+ BottomSheetBackdrop,
+ BottomSheetModal,
+ BottomSheetModalProvider,
+ BottomSheetScrollView,
+} from '@gorhom/bottom-sheet'
+import useBackHandler from '@hooks/useBackHandler'
+import { PublicKey } from '@solana/web3.js'
+import React, {
+ Ref,
+ forwardRef,
+ useCallback,
+ useImperativeHandle,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
+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 '@config/theme/theme'
+import { Portal } from '@gorhom/portal'
+import { useCreateExplorerUrl } from '../../utils/constants/urls'
+import { Activity } from '../../types/activity'
+import TransactionLineItem from './TransactionLineItem'
+import { useTxnDetails } from './useTxn'
+
+type DetailData = { item: Activity; accountAddress: string; mint: PublicKey }
+
+type Props = BoxProps
+
+export type TransactionDetailSelectorRef = {
+ showTransaction: (DetailData) => void
+}
+
+const TransactionDetailSelector = forwardRef(
+ (_: Props, ref: Ref) => {
+ useImperativeHandle(ref, () => ({ showTransaction }))
+
+ const { t } = useTranslation()
+ const bottomSheetModalRef = useRef(null)
+ const [detailData, setDetailData] = useState()
+ const [contentHeight, setContentHeight] = useState(0)
+ const { handleDismiss, setIsShowing } = useBackHandler(bottomSheetModalRef)
+
+ const { item: txn, mint } = detailData || {}
+
+ const {
+ amount,
+ amountTitle,
+ color,
+ fee,
+ feePayer,
+ icon,
+ paymentsReceived,
+ paymentsSent,
+ time,
+ title,
+ } = useTxnDetails(mint, txn)
+ const createExplorerUrl = useCreateExplorerUrl()
+
+ const snapPoints = useMemo(() => {
+ let maxHeight: number | string = '90%'
+ if (contentHeight > 0) {
+ maxHeight = contentHeight
+ }
+ return ['50%', maxHeight]
+ }, [contentHeight])
+
+ const showTransaction = useCallback(
+ (data: DetailData) => {
+ setDetailData(data)
+ bottomSheetModalRef.current?.present()
+ setIsShowing(true)
+ },
+ [setIsShowing],
+ )
+
+ const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
+
+ const renderBackdrop = useCallback(
+ (props) => (
+
+ ),
+ [],
+ )
+
+ const backgroundComponent = useCallback(() => {
+ return (
+
+ )
+ }, [])
+
+ const handleComponent = useCallback(() => , [])
+
+ const handleContentLayout = useCallback((e: LayoutChangeEvent) => {
+ setContentHeight(e.nativeEvent.layout.height)
+ }, [])
+
+ return (
+
+
+
+
+
+
+
+ {paymentsSent.map(({ amount: amt }, index) => (
+
+
+
+ ))}
+
+ {paymentsReceived.map(({ amount: amt }, index) => (
+
+
+
+ ))}
+
+ {!!amountTitle && (
+
+ )}
+
+ {!!fee && (
+
+ )}
+
+
+
+ {!txn?.pending && (
+
+ )}
+
+
+
+
+
+
+
+ )
+ },
+)
+
+export default TransactionDetailSelector
diff --git a/src/features/account/TransactionLineItem.tsx b/src/features/wallet/TransactionLineItem.tsx
similarity index 89%
rename from src/features/account/TransactionLineItem.tsx
rename to src/features/wallet/TransactionLineItem.tsx
index 9753652c5..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'
@@ -37,8 +41,8 @@ const TransactionLineItem = ({
bodyEndColor,
}: Props) => {
const { primaryText } = useColors()
- const linkHitSlop = useHitSlop('s')
- const copyHitSlop = useVerticalHitSlop('s')
+ const linkHitSlop = useHitSlop('2')
+ const copyHitSlop = useVerticalHitSlop('2')
const { contacts, sortedAccounts } = useAccountStorage()
const copyText = useCopyText()
const navigation = useNavigation()
@@ -113,15 +117,15 @@ const TransactionLineItem = ({
return (
@@ -148,7 +152,7 @@ const TransactionLineItem = ({
numberOfLines={3}
adjustsFontSizeToFit
flexShrink={1}
- variant="body1"
+ variant="textMdRegular"
color={bodyColor || 'primaryText'}
marginLeft={icon ? 'xs' : 'none'}
>
@@ -162,7 +166,7 @@ const TransactionLineItem = ({
adjustsFontSizeToFit
flex={1}
textAlign="right"
- variant="body1"
+ variant="textMdRegular"
color={bodyEndColor || 'primaryText'}
marginLeft={icon ? 'xs' : 'none'}
>
@@ -179,7 +183,7 @@ const TransactionLineItem = ({
diff --git a/src/features/account/TxnListItem.tsx b/src/features/wallet/TxnListItem.tsx
similarity index 65%
rename from src/features/account/TxnListItem.tsx
rename to src/features/wallet/TxnListItem.tsx
index fab5acc52..00041ca66 100644
--- a/src/features/account/TxnListItem.tsx
+++ b/src/features/wallet/TxnListItem.tsx
@@ -1,9 +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 '@config/theme/theme'
import { Activity } from '../../types/activity'
import useTxn from './useTxn'
@@ -14,7 +16,14 @@ type Props = {
isLast: boolean
onPress: (item: Activity) => void
}
-const TxnListItem = ({ mint, item, now, isLast, onPress }: Props) => {
+const TxnListItem = ({
+ mint,
+ item,
+ now,
+ isLast,
+ onPress,
+ ...rest
+}: Props & BoxProps) => {
const { listIcon, title, color, time, getAmount } = useTxn(mint, item, {
now,
})
@@ -27,12 +36,15 @@ const TxnListItem = ({ mint, item, now, isLast, onPress }: Props) => {
return (
- {listIcon}
+ {listIcon}
{item.pending && (
{
)}
-
- {title}
-
+
+ {title}
+
{time}
-
-
+
+
{amt}
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 1e97899dc..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,
@@ -96,7 +96,7 @@ const useTxn = (
const color = useMemo((): Color => {
switch (item?.type as TxnType) {
case 'payment_v2':
- return isSending ? 'blueBright500' : 'greenBright500'
+ return isSending ? 'blue.light-500' : 'green.light-500'
default:
return 'primaryText'
}
diff --git a/src/hooks/useAmountLocked.ts b/src/hooks/useAmountLocked.ts
new file mode 100644
index 000000000..382c4daa3
--- /dev/null
+++ b/src/hooks/useAmountLocked.ts
@@ -0,0 +1,81 @@
+import { getPositionKeysForOwner } from '@helium/voter-stake-registry-sdk'
+import { PublicKey } from '@solana/web3.js'
+import { useMemo } from 'react'
+import { useAsync } from 'react-async-hook'
+import {
+ useHeliumVsrState,
+ usePositions,
+} from '@helium/voter-stake-registry-hooks'
+import { BN } from 'bn.js'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { useCurrentWallet } from './useCurrentWallet'
+
+const useAmountLocked = (mint: PublicKey) => {
+ const wallet = useCurrentWallet()
+ const { anchorProvider, connection } = useSolana()
+
+ const { positions: contextPositions, mint: govMint } = useHeliumVsrState()
+
+ const useContextPositions = useMemo(
+ () => !!govMint?.equals(mint),
+ [govMint, mint],
+ )
+
+ const args = useMemo(
+ () =>
+ wallet &&
+ mint &&
+ connection && {
+ wallet,
+ mint,
+ provider: anchorProvider,
+ },
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [wallet?.toBase58(), mint.toBase58(), connection, anchorProvider],
+ )
+
+ const { result } = useAsync(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ async (a: any | undefined, useContext: boolean) => {
+ if (a && !useContext) {
+ return getPositionKeysForOwner(a)
+ }
+ },
+ [args, useContextPositions],
+ )
+
+ const { accounts: fetchedPositions } = usePositions(result?.positions)
+
+ const positions = useMemo(
+ () =>
+ useContextPositions
+ ? contextPositions
+ : fetchedPositions?.map((fetched) => fetched.info),
+ [useContextPositions, contextPositions, fetchedPositions],
+ )
+
+ const { amountLocked } = useMemo(() => {
+ if (positions && positions.length) {
+ let amountL = new BN(0)
+ positions.forEach((position) => {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ if (position && !position.isProxiedToMe) {
+ amountL = amountL.add(position.amountDepositedNative)
+ }
+ })
+
+ return {
+ amountLocked: amountL,
+ }
+ }
+
+ return {}
+ }, [positions])
+
+ return {
+ amountLocked,
+ }
+}
+
+export default useAmountLocked
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 15a368161..5474a96e7 100644
--- a/src/hooks/useCollectables.ts
+++ b/src/hooks/useCollectables.ts
@@ -1,6 +1,9 @@
import { useCallback, useEffect, useRef } from 'react'
import { useSelector } from 'react-redux'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
+import { WrappedConnection } from '@utils/WrappedConnection'
+import { useAccountStorage } from '@config/storage/AccountStorageProvider'
+import { useSolana } from '@features/solana/SolanaProvider'
+import { CompressedNFT } from '../types/solana'
import { RootState } from '../store/rootReducer'
import {
fetchCollectables,
@@ -8,11 +11,16 @@ import {
collectables as collectablesSli,
} from '../store/slices/collectablesSlice'
import { useAppDispatch } from '../store/store'
-import { onLogs, removeAccountChangeListener } from '../utils/solanaUtils'
-import { useSolana } from '../solana/SolanaProvider'
+import {
+ getNFTs,
+ groupNFTs,
+ onLogs,
+ removeAccountChangeListener,
+} from '../utils/solanaUtils'
const useCollectables = (): WalletCollectables & {
refresh: () => void
+ fetchAllCollectablesByGroup: () => Promise>
} => {
const { cluster, anchorProvider } = useSolana()
const dispatch = useAppDispatch()
@@ -58,6 +66,29 @@ const useCollectables = (): WalletCollectables & {
accountSubscriptionId.current = subId
}, [anchorProvider, currentAccount, dispatch, refresh])
+ const fetchAllCollectablesByGroup = useCallback(async () => {
+ if (!anchorProvider) return {}
+
+ let page = 1
+ let isLastPage = false
+ let fetchedCollectables: CompressedNFT[] = []
+
+ while (!isLastPage) {
+ const response = await getNFTs(
+ anchorProvider?.publicKey,
+ anchorProvider?.connection as WrappedConnection,
+ page,
+ )
+ fetchedCollectables = fetchedCollectables.concat(response)
+ isLastPage = response.length === 0
+ page += 1
+ }
+
+ const groupedCollectablesWithMeta = await groupNFTs(fetchedCollectables)
+
+ return groupedCollectablesWithMeta
+ }, [anchorProvider])
+
if (
!currentAccount?.solanaAddress ||
!collectables[cluster]?.[currentAccount?.solanaAddress]
@@ -65,14 +96,15 @@ const useCollectables = (): WalletCollectables & {
return {
loading: false,
collectables: {},
- collectablesWithMeta: {},
refresh,
+ fetchAllCollectablesByGroup,
}
}
return {
...collectables[cluster][currentAccount?.solanaAddress],
refresh,
+ fetchAllCollectablesByGroup,
}
}
export default useCollectables
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 425d8d424..35e402a3c 100644
--- a/src/hooks/useDerivationAccounts.ts
+++ b/src/hooks/useDerivationAccounts.ts
@@ -1,6 +1,5 @@
import { Keypair as HeliumKeypair, Mnemonic } from '@helium/crypto'
-import { Asset, getAssetsByOwner, truthy } from '@helium/spl-utils'
-import { TOKEN_PROGRAM_ID } from '@solana/spl-token'
+import { Asset, truthy } from '@helium/spl-utils'
import {
AccountInfo,
Keypair,
@@ -14,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) {
@@ -132,27 +131,27 @@ export const useDerivationAccounts = ({ mnemonic }: { mnemonic?: string }) => {
if (keypair) {
let needsMigrated = false
- const [balance, tokens, nfts] = await Promise.all([
+ const [balance] = await Promise.all([
retryWithBackoff(() =>
connection.getBalance(keypair.publicKey),
),
- retryWithBackoff(() =>
- connection.getTokenAccountsByOwner(
- keypair.publicKey,
- {
- programId: TOKEN_PROGRAM_ID,
- },
- ),
- ),
- retryWithBackoff(() =>
- getAssetsByOwner(
- connection.rpcEndpoint,
- keypair.publicKey.toBase58(),
- {
- limit: 10,
- },
- ),
- ),
+ // retryWithBackoff(() =>
+ // connection.getTokenAccountsByOwner(
+ // keypair.publicKey,
+ // {
+ // programId: TOKEN_PROGRAM_ID,
+ // },
+ // ),
+ // ),
+ // retryWithBackoff(() =>
+ // getAssetsByOwner(
+ // connection.rpcEndpoint,
+ // keypair.publicKey.toBase58(),
+ // {
+ // limit: 10,
+ // },
+ // ),
+ // ),
])
if (derivationPath === heliumDerivation(-1)) {
@@ -168,9 +167,7 @@ export const useDerivationAccounts = ({ mnemonic }: { mnemonic?: string }) => {
derivationPath,
keypair,
balance,
- tokens,
needsMigrated,
- nfts,
} as ResolvedPath
}
}),
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.ts b/src/hooks/useMetaplexMetadata.tsx
similarity index 73%
rename from src/hooks/useMetaplexMetadata.ts
rename to src/hooks/useMetaplexMetadata.tsx
index 56f678925..ffda9e3dc 100644
--- a/src/hooks/useMetaplexMetadata.ts
+++ b/src/hooks/useMetaplexMetadata.tsx
@@ -9,7 +9,10 @@ import axios from 'axios'
import { useMemo } from 'react'
import { useAsync } from 'react-async-hook'
import { useAccount } from '@helium/account-fetch-cache-hooks'
-
+import { useSelector } from 'react-redux'
+import { RootState } from '@store/rootReducer'
+import { useAppDispatch } from '@store/store'
+import { tokensSlice } from '@store/slices/tokensSlice'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cache: Record> = {}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -79,6 +82,16 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): {
symbol: string | undefined
name: string | undefined
} {
+ const dispatch = useAppDispatch()
+ const { tokens } = useSelector((state: RootState) => state.tokens)
+
+ const cachedToken = useMemo(() => {
+ if (mint) {
+ return tokens[mint.toBase58()]
+ }
+ return undefined
+ }, [mint, tokens])
+
const metadataAddr = useMemo(() => {
if (mint) {
return getMetadataId(mint)
@@ -91,9 +104,23 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): {
METADATA_PARSER,
)
- const { result: json, loading: jsonLoading } = useAsync(getMetadata, [
- metadataAcc?.data.uri.trim(),
- ])
+ const { result: json, loading: jsonLoading } = useAsync(async () => {
+ if (!mint) return
+ let meta
+ try {
+ meta = await getMetadata(metadataAcc?.data.uri.trim())
+ } catch {}
+
+ dispatch(
+ tokensSlice.actions.setToken({
+ mint: mint.toBase58(),
+ name: metadataAcc?.data?.name || meta?.name,
+ symbol: metadataAcc?.data?.symbol || meta?.symbol,
+ img: meta?.image,
+ }),
+ )
+ return meta || metadataAcc
+ }, [mint, dispatch, metadataAcc])
if (mint?.equals(NATIVE_MINT)) {
return {
@@ -125,6 +152,20 @@ export function useMetaplexMetadata(mint: PublicKey | undefined): {
}
}
+ if (cachedToken) {
+ return {
+ metadata: metadataAcc,
+ loading: false,
+ json: {
+ name: cachedToken.name,
+ symbol: cachedToken.symbol,
+ image: cachedToken.img,
+ },
+ symbol: cachedToken.symbol,
+ name: cachedToken.name,
+ }
+ }
+
return {
loading: jsonLoading || loading,
json,
diff --git a/src/hooks/useNetworkColor.tsx b/src/hooks/useNetworkColor.tsx
index 2941617bc..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,
@@ -14,7 +14,7 @@ export default ({
return useMemo(() => {
if (netType === NetTypes.TESTNET) {
if (muted) {
- return 'lividBrown'
+ return 'orange.dark-500'
}
return 'testnet'
}
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 3e1d3b40e..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,
@@ -33,11 +33,7 @@ import {
updateRewardsDestinations,
} from '../store/slices/solanaSlice'
import { useAppDispatch } from '../store/store'
-import {
- Collectable,
- CompressedNFT,
- HotspotWithPendingRewards,
-} from '../types/solana'
+import { CompressedNFT, HotspotWithPendingRewards } from '../types/solana'
export default () => {
const { cluster, anchorProvider } = useSolana()
@@ -118,7 +114,7 @@ export default () => {
)
const submitCollectable = useCallback(
- async (collectable: CompressedNFT | Collectable, payee: string) => {
+ async (collectable: CompressedNFT, payee: string) => {
if (
!currentAccount?.solanaAddress ||
!anchorProvider ||
@@ -127,22 +123,17 @@ export default () => {
throw new Error(t('errors.account'))
}
- const compressedNFT = collectable as CompressedNFT
- const nft = collectable as Collectable
-
- const transferTxn = compressedNFT?.compression?.compressed
+ const transferTxn = collectable?.compression?.compressed
? await solUtils.transferCompressedCollectable(
anchorProvider,
currentAccount.solanaAddress,
- currentAccount.address,
- compressedNFT,
+ collectable,
payee,
)
: await solUtils.transferCollectable(
anchorProvider,
currentAccount.solanaAddress,
- currentAccount.address,
- nft,
+ collectable,
payee,
)
diff --git a/src/navigation/RootNavigator.tsx b/src/navigation/RootNavigator.tsx
deleted file mode 100644
index 9ad2f2f55..000000000
--- a/src/navigation/RootNavigator.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-import {
- HELIUM_DERIVATION,
- keypairFromSeed,
- solanaDerivation,
-} from '@hooks/useDerivationAccounts'
-import { useNavigation } from '@react-navigation/native'
-import {
- StackNavigationOptions,
- createStackNavigator,
-} from '@react-navigation/stack'
-import { useAccountStorage } from '@storage/AccountStorageProvider'
-import { CSAccount } from '@storage/cloudStorage'
-import { getSecureAccount } from '@storage/secureStorage'
-import { useColors } from '@theme/themeHooks'
-import * as bip39 from 'bip39'
-import React, { memo, useCallback, useEffect, useRef } from 'react'
-import { useAsync, useAsyncCallback } from 'react-async-hook'
-import changeNavigationBarColor from 'react-native-navigation-bar-color'
-import Toast from 'react-native-simple-toast'
-import { useSelector } from 'react-redux'
-import ScanQrCodeScreen from '../features/keystone/ScanQrCodeScreen'
-import SelectKeystoneAccountsScreen from '../features/keystone/SelectKeystoneAccountsScreen'
-import ConnectedWallets, {
- ConnectedWalletsRef,
-} from '../features/account/ConnectedWallets'
-import DappLoginScreen from '../features/dappLogin/DappLoginScreen'
-import { HomeNavigationProp } from '../features/home/homeTypes'
-import OnboardingNavigator from '../features/onboarding/OnboardingNavigator'
-import { useOnboarding } from '../features/onboarding/OnboardingProvider'
-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 { RootState } from '../store/rootReducer'
-import { appSlice } from '../store/slices/appSlice'
-import { useAppDispatch } from '../store/store'
-import TabBarNavigator from './TabBarNavigator'
-import {
- RootNavigationProp,
- RootStackParamList,
- TabBarNavigationProp,
-} from './rootTypes'
-
-const screenOptions = { headerShown: false } as StackNavigationOptions
-
-const RootNavigator = () => {
- const navigation = useNavigation<
- RootNavigationProp & HomeNavigationProp & TabBarNavigationProp
- >()
- const colors = useColors()
- const RootStack = createStackNavigator()
- const connectedWalletsRef = useRef(null)
- const dispatch = useAppDispatch()
- const { setOnboardingData, onboardingData } = useOnboarding()
- const { currentAccount, accounts } = useAccountStorage()
- const { result: seed } = useAsync(async () => {
- if (currentAccount) {
- const storage = await getSecureAccount(currentAccount.address)
- return bip39.mnemonicToSeedSync(storage?.mnemonic?.join(' ') || '', '')
- }
- }, [currentAccount])
-
- useEffect(() => {
- changeNavigationBarColor(colors.primaryBackground, true, false)
- }, [colors.primaryBackground])
-
- const handleAddNew = useCallback(() => {
- navigation.navigate('AddNewAccountNavigator')
- }, [navigation])
-
- const { execute: handleAddSub } = useAsyncCallback(async (acc: CSAccount) => {
- try {
- if (!seed || !acc?.derivationPath) {
- throw new Error('Missing seed or derivation path')
- }
- const currentPath = acc.derivationPath
- const takenAddresses = new Set(
- Object.values(accounts || {}).map((a) => a.solanaAddress),
- )
- let currentAccountNum =
- currentPath === HELIUM_DERIVATION
- ? 0
- : Number(currentPath.split('/')[3].replace("'", '')) + 1
- let derivationPath = solanaDerivation(currentAccountNum, 0)
- let keypair = await keypairFromSeed(seed, derivationPath)
- while (
- currentAccountNum < 100 &&
- (!keypair || takenAddresses.has(keypair.publicKey.toBase58()))
- ) {
- currentAccountNum += 1
- derivationPath = solanaDerivation(currentAccountNum, 0)
- keypair = await keypairFromSeed(seed, derivationPath)
- }
- if (currentAccountNum >= 100) {
- throw new Error('More than 100 accounts are not supported')
- }
- if (keypair) {
- const words = (await getSecureAccount(acc.address))?.mnemonic
- setOnboardingData({
- ...onboardingData,
- words,
- paths: [
- {
- derivationPath,
- keypair,
- },
- ],
- })
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- navigation.navigate('TabBarNavigator', {
- screen: 'Home',
- params: {
- screen: 'AccountAssignScreen',
- params: {
- words,
- },
- },
- })
- connectedWalletsRef.current?.hide()
- }
- } catch (e: any) {
- Toast.show(e.message || e.toString())
- }
- })
-
- const showConnectedWallets = useSelector(
- (state: RootState) => state.app.showConnectedWallets,
- )
-
- const onClose = useCallback(() => {
- dispatch(appSlice.actions.toggleConnectedWallets())
- }, [dispatch])
-
- useEffect(() => {
- if (showConnectedWallets) {
- connectedWalletsRef.current?.show()
- }
- }, [showConnectedWallets])
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default memo(RootNavigator)
diff --git a/src/navigation/TabBarNavigator.tsx b/src/navigation/TabBarNavigator.tsx
deleted file mode 100644
index 9ffdc6a13..000000000
--- a/src/navigation/TabBarNavigator.tsx
+++ /dev/null
@@ -1,210 +0,0 @@
-import React, { FC, useCallback, useEffect, useMemo } from 'react'
-import { SvgProps } from 'react-native-svg'
-import {
- BottomTabBarProps,
- createBottomTabNavigator,
-} from '@react-navigation/bottom-tabs'
-import { Edge, useSafeAreaInsets } from 'react-native-safe-area-context'
-import Dollar from '@assets/images/dollar.svg'
-import Gem from '@assets/images/collectableIcon.svg'
-import Transactions from '@assets/images/transactions.svg'
-import Governance from '@assets/images/courthouse.svg'
-import { Portal } from '@gorhom/portal'
-import NavBar, { NavBarHeight } from '@components/NavBar'
-import { Color } from '@theme/theme'
-import SafeAreaBox from '@components/SafeAreaBox'
-import Box from '@components/Box'
-import useEnrichedTransactions from '@hooks/useEnrichedTransactions'
-import useHaptic from '@hooks/useHaptic'
-import Globe from '@assets/images/earth-globe.svg'
-import { useDispatch } from 'react-redux'
-import { useGovernance } from '@storage/GovernanceProvider'
-import GovernanceNavigator from '../features/governance/GovernanceNavigator'
-import { useAppStorage } from '../storage/AppStorageProvider'
-import { useAccountStorage } from '../storage/AccountStorageProvider'
-import SolanaMigration from '../features/migration/SolanaMigration'
-import HomeNavigator from '../features/home/HomeNavigator'
-import CollectablesNavigator from '../features/collectables/CollectablesNavigator'
-import ActivityNavigator from '../features/activity/ActivityNavigator'
-import BrowserNavigator from '../features/browser/BrowserNavigator'
-import { appSlice } from '../store/slices/appSlice'
-import { useSolana } from '../solana/SolanaProvider'
-
-const Tab = createBottomTabNavigator()
-
-function MyTabBar({ state, navigation }: BottomTabBarProps) {
- const { hasNewTransactions, resetNewTransactions } = useEnrichedTransactions()
- const { triggerImpact } = useHaptic()
- const { hasUnseenProposals } = useGovernance()
-
- const tabData = useMemo((): Array<{
- value: string
- Icon: FC
- iconColor: Color
- hasBadge?: boolean
- }> => {
- return [
- { value: 'account', Icon: Dollar, iconColor: 'white' },
- {
- value: 'collectables',
- Icon: Gem,
- iconColor: 'white',
- hasBadge: false,
- },
- {
- value: 'activity',
- Icon: Transactions,
- iconColor: 'white',
- hasBadge: hasNewTransactions && state.index !== 2,
- },
- {
- value: 'governance',
- Icon: Governance,
- iconColor: 'white',
- hasBadge: hasUnseenProposals && state.index !== 3,
- },
- { value: 'browser', Icon: Globe, iconColor: 'white' },
- ]
- }, [hasNewTransactions, hasUnseenProposals, state.index])
-
- const selectedValue = tabData[state.index].value
- const safeEdges = useMemo(() => ['bottom'] as Edge[], [])
-
- const onPress = useCallback(
- (type: string) => {
- triggerImpact('light')
- const index = tabData.findIndex((item) => item.value === type)
- const isSelected = selectedValue === type
- const event = navigation.emit({
- type: 'tabPress',
- target: state.routes[index || 0].key,
- canPreventDefault: true,
- })
-
- // Check if activty tab is selected and has new transactions
- if (selectedValue === 'activity' && hasNewTransactions) {
- resetNewTransactions()
- }
-
- if (!isSelected && !event.defaultPrevented) {
- // The `merge: true` option makes sure that the params inside the tab screen are preserved
- navigation.navigate({
- name: state.routes[index || 0].name,
- merge: true,
- params: undefined,
- })
- }
- },
- [
- hasNewTransactions,
- navigation,
- resetNewTransactions,
- selectedValue,
- state.routes,
- tabData,
- triggerImpact,
- ],
- )
-
- const onLongPress = useCallback(
- (type: string) => {
- const index = tabData.findIndex((item) => item.value === type)
-
- navigation.emit({
- type: 'tabLongPress',
- target: state.routes[index || 0].key,
- })
- },
- [navigation, state.routes, tabData],
- )
-
- return (
-
-
-
-
-
-
-
- )
-}
-
-const TabBarNavigator = () => {
- const dispatch = useDispatch()
-
- const { doneSolanaMigration, manualMigration } = useAppStorage()
- const { cluster, updateCluster } = useSolana()
- const { bottom } = useSafeAreaInsets()
- const { currentAccount } = useAccountStorage()
- const { anchorProvider } = useSolana()
-
- useEffect(() => {
- dispatch(appSlice.actions.setShowBanner(cluster === 'devnet'))
- }, [dispatch, cluster])
-
- // Switch to mainnet-beta if migration is complete & user hasn't already migrated
- useEffect(() => {
- if (!currentAccount?.solanaAddress) {
- return
- }
-
- if (
- !doneSolanaMigration['mainnet-beta']?.includes(
- currentAccount.solanaAddress,
- ) &&
- !manualMigration['mainnet-beta'].includes(currentAccount.solanaAddress)
- ) {
- updateCluster('mainnet-beta')
- }
- }, [
- currentAccount,
- doneSolanaMigration,
- cluster,
- manualMigration,
- updateCluster,
- ])
-
- // keystone account do not need to migrate
- return (
- <>
- {currentAccount?.solanaAddress &&
- !currentAccount?.keystoneDevice &&
- anchorProvider &&
- !doneSolanaMigration[cluster]?.includes(currentAccount.solanaAddress) &&
- !manualMigration[cluster]?.includes(currentAccount.solanaAddress) && (
-
-
-
- )}
- }
- screenOptions={{
- headerShown: false,
- lazy: true,
- }}
- sceneContainerStyle={{
- paddingBottom: NavBarHeight + bottom,
- }}
- >
-
-
-
-
-
-
- >
- )
-}
-
-export default TabBarNavigator
diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts
index 3f0ba5102..743ffaa1e 100644
--- a/src/store/rootReducer.ts
+++ b/src/store/rootReducer.ts
@@ -12,6 +12,7 @@ import notificationsReducer, {
import balancesReducer, {
name as balancesSliceName,
} from './slices/balancesSlice'
+import tokensReducer, { name as tokensSliceName } from './slices/tokensSlice'
import collectablesReducer, {
name as collectablesSliceName,
} from './slices/collectablesSlice'
@@ -28,6 +29,12 @@ const solanaConfig = {
blacklist: ['payment'],
}
+const appConfig = {
+ key: appSliceName,
+ storage: AsyncStorage,
+ blacklist: ['rootSheetPosition'],
+}
+
const notificationsConfig = {
key: notificationsSliceName,
storage: AsyncStorage,
@@ -40,6 +47,12 @@ const balancesConfig = {
blacklist: ['balancesLoading'],
}
+const tokensConfig = {
+ key: tokensSliceName,
+ storage: AsyncStorage,
+ blacklist: [],
+}
+
const reducer = combineReducers({
[solanaStatusApi.reducerPath]: solanaStatusReducer,
[collectablesSliceName]: collectablesReducer,
@@ -50,9 +63,10 @@ const reducer = combineReducers({
notificationsReducer,
),
[authSliceName]: authReducer,
- [appSliceName]: appReducer,
+ [appSliceName]: persistReducer(appConfig, appReducer),
[hotspotSliceName]: hotspotReducer,
[browserSliceName]: browserReducer,
+ [tokensSliceName]: persistReducer(tokensConfig, tokensReducer),
})
export const rootReducer = (state: RootState, action: AnyAction) => {
diff --git a/src/store/slices/appSlice.ts b/src/store/slices/appSlice.ts
index 435dec1e5..b9e12e419 100644
--- a/src/store/slices/appSlice.ts
+++ b/src/store/slices/appSlice.ts
@@ -2,13 +2,12 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { Cluster } from '@solana/web3.js'
export type AppState = {
- showConnectedWallets: boolean
showBanner: boolean
cluster?: Cluster
+ rootSheetPosition?: number
}
const initialState: AppState = {
- showConnectedWallets: false,
showBanner: true,
}
@@ -19,12 +18,15 @@ const appSlice = createSlice({
setCluster: (state, action: PayloadAction) => {
state.cluster = action.payload
},
- toggleConnectedWallets: (state) => {
- state.showConnectedWallets = !state.showConnectedWallets
- },
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 d7a8f1ca3..4a7a4d16f 100644
--- a/src/store/slices/collectablesSlice.ts
+++ b/src/store/slices/collectablesSlice.ts
@@ -2,56 +2,80 @@ 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 { Collectable } from '../../types/solana'
+import { CSAccount } from '@config/storage/cloudStorage'
+import { CompressedNFT } from '../../types/solana'
import * as solUtils from '../../utils/solanaUtils'
export type WalletCollectables = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
collectables: Record
- collectablesWithMeta: Record
loading: boolean
}
export type CollectablesByWallet = Record
-export type CollectablesByCluster = Record
+export type CollectablesByCluster = {
+ 'mainnet-beta': CollectablesByWallet
+ devnet: CollectablesByWallet
+ testnet: CollectablesByWallet
+ approvedCollections: string[]
+}
const initialState: CollectablesByCluster = {
'mainnet-beta': {},
devnet: {},
testnet: {},
+ approvedCollections: solUtils.heliumNFTs(),
}
export const fetchCollectables = createAsyncThunk(
'collectables/fetchCollectables',
- async ({
- account,
- connection,
- }: {
- account: CSAccount
- cluster: Cluster
- connection: Connection
- }) => {
+ async (
+ {
+ account,
+ connection,
+ }: {
+ account: CSAccount
+ cluster: Cluster
+ connection: Connection
+ },
+ { getState },
+ ) => {
if (!account.solanaAddress) throw new Error('Solana address missing')
-
const pubKey = new PublicKey(account.solanaAddress)
- const fetchedCollectables = await solUtils.getNFTs(
- pubKey,
- connection as WrappedConnection,
- )
- const groupedCollectables = solUtils.groupNFTs(fetchedCollectables)
+ let page = 1
+ let isLastPage = false
+ let fetchedCollectables: CompressedNFT[] = []
+
+ const { collectables } = (await getState()) as {
+ collectables: CollectablesByCluster
+ }
+
+ while (!isLastPage) {
+ const response = await solUtils.getNFTs(
+ pubKey,
+ connection as WrappedConnection,
+ page,
+ )
+ fetchedCollectables = fetchedCollectables.concat(response)
+ isLastPage = response.length === 0
+ page += 1
+ }
+
+ const approvedCollections =
+ collectables.approvedCollections || solUtils.heliumNFTs()
- const collectablesWithMetadata = await solUtils.getNFTsMetadata(
- fetchedCollectables,
- )
+ const filteredCollectables = fetchedCollectables.filter((collectable) => {
+ const collection = collectable?.grouping?.find(
+ (k) => k.group_key === 'collection',
+ )?.group_value
- const groupedCollectablesWithMeta = solUtils.groupNFTsWithMetaData(
- collectablesWithMetadata,
- )
+ return approvedCollections.includes(collection)
+ })
+
+ const groupedCollectables = solUtils.groupNFTs(filteredCollectables)
return {
groupedCollectables,
- groupedCollectablesWithMeta,
}
},
)
@@ -73,6 +97,22 @@ const collectables = createSlice({
}
state[cluster][address] = { ...state[cluster][address], loading: false }
},
+ toggleApprovedCollection: (
+ state,
+ action: PayloadAction<{ collection: string }>,
+ ) => {
+ if (!state.approvedCollections) {
+ state.approvedCollections = []
+ }
+
+ if (state.approvedCollections.includes(action.payload.collection)) {
+ state.approvedCollections = state.approvedCollections.filter(
+ (c) => c !== action.payload.collection,
+ )
+ } else {
+ state.approvedCollections.push(action.payload.collection)
+ }
+ },
},
extraReducers: (builder) => {
builder.addCase(fetchCollectables.pending, (state, action) => {
@@ -81,7 +121,6 @@ const collectables = createSlice({
const address = action.meta.arg.account.solanaAddress
const prev = state[cluster][address] || {
- collectablesWithMeta: {},
collectables: {},
}
state[cluster][address] = {
@@ -92,14 +131,12 @@ const collectables = createSlice({
builder.addCase(fetchCollectables.fulfilled, (state, action) => {
if (!action.meta.arg?.account.solanaAddress) return state
const { cluster } = action.meta.arg
- const { groupedCollectables, groupedCollectablesWithMeta } =
- action.payload
+ const { groupedCollectables } = action.payload
const address = action.meta.arg.account.solanaAddress
state[cluster][address] = {
collectables: groupedCollectables,
- collectablesWithMeta: groupedCollectablesWithMeta,
loading: false,
}
})
@@ -109,7 +146,6 @@ const collectables = createSlice({
const address = action.meta.arg.account.solanaAddress
const prev = state[cluster][address] || {
- collectablesWithMeta: {},
collectables: {},
}
state[cluster][address] = {
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/slices/tokensSlice.ts b/src/store/slices/tokensSlice.ts
new file mode 100644
index 000000000..d69653cb1
--- /dev/null
+++ b/src/store/slices/tokensSlice.ts
@@ -0,0 +1,30 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit'
+
+type Token = {
+ mint: string
+ symbol: string
+ img: string
+ name: string
+}
+
+export type TokensState = {
+ tokens: Record
+}
+
+const initialState: TokensState = {
+ tokens: {},
+}
+
+const tokensSlice = createSlice({
+ name: 'tokens',
+ initialState,
+ reducers: {
+ setToken: (state, action: PayloadAction) => {
+ state.tokens[action.payload.mint] = action.payload
+ },
+ },
+})
+
+const { reducer, name } = tokensSlice
+export { name, tokensSlice }
+export default reducer
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/theme/theme.ts b/src/theme/theme.ts
deleted file mode 100644
index a440f487f..000000000
--- a/src/theme/theme.ts
+++ /dev/null
@@ -1,425 +0,0 @@
-import { createTheme } from '@shopify/restyle'
-
-export const Font = {
- italic: 'DMSans-Italic',
- regular: 'DMSans-Regular',
- mediumItalic: 'DMSans-MediumItalic',
- medium: 'DMSans-Medium',
- bold: 'DMSans-Bold',
- boldItalic: 'DMSans-BoldItalic',
-}
-
-const textVariants = {
- h0: {
- fontFamily: Font.regular,
- fontSize: 42,
- lineHeight: 44,
- color: 'primaryText',
- },
- h1: {
- fontFamily: Font.regular,
- fontSize: 37,
- color: 'primaryText',
- },
- h2: {
- fontFamily: Font.regular,
- fontSize: 33,
- color: 'primaryText',
- },
- h3: {
- fontFamily: Font.regular,
- fontSize: 27,
- color: 'primaryText',
- },
- h4: {
- fontFamily: Font.regular,
- fontSize: 22,
- color: 'primaryText',
- },
- subtitle1: {
- fontFamily: Font.medium,
- fontSize: 20,
- color: 'primaryText',
- },
- subtitle2: {
- fontFamily: Font.medium,
- fontSize: 19,
- color: 'primaryText',
- },
- subtitle3: {
- fontFamily: Font.medium,
- fontSize: 17,
- color: 'primaryText',
- },
- subtitle4: {
- fontFamily: Font.medium,
- fontSize: 14,
- color: 'primaryText',
- },
- body0: {
- fontFamily: Font.regular,
- fontSize: 21,
- color: 'primaryText',
- },
- body1: {
- fontFamily: Font.regular,
- fontSize: 16,
- color: 'primaryText',
- },
- body2: {
- fontFamily: Font.regular,
- fontSize: 14,
- color: 'primaryText',
- },
- body3: {
- fontFamily: Font.regular,
- fontSize: 12,
- color: 'primaryText',
- },
- body4: {
- fontFamily: Font.regular,
- fontSize: 8,
- color: 'primaryText',
- },
- regular: {
- fontFamily: Font.regular,
- },
- medium: {
- fontFamily: Font.medium,
- },
- bold: {
- fontFamily: Font.bold,
- },
-}
-
-/**
- * Use https://www.hexdictionary.com/ to determine color names, for example https://www.hexdictionary.com/color/d23e72.
- * https://elektrobild.org/tools/sort-colors can be used to sort colors.
- */
-
-const palette = {
- aquaMarine: '#69DBB3',
-
- black200: '#414141',
- black300: '#464646',
- black400: '#333333',
- black500: '#2B2B2B',
- black600: '#212121',
- black650: '#191919',
- black700: '#161616',
- black750: '#1A1A1A',
- black800: '#1A1C22',
- black850: '#131313',
- black900: '#0E0E0E',
- black900_9A: '#0000009A',
-
- black: '#000000',
-
- blue500: '#3B82F6',
- blue950: '#172554',
- blueBorder: 'rgba(59, 130, 246, 0.25)',
- hntBlue: '#2755F8',
- mobileDarkBlue: '#00273D',
- mobileBlue: '#009EF8',
- iotDarkGreen: '#053919',
- iotGreen: '#26ED75',
-
- green500: '#22C55E',
- green950: '#052E16',
- greenBorder: 'rgba(34, 197, 94, 0.25)',
-
- orange500: '#f97316',
- orange950: '#431407',
- orangeBorder: 'rgba(245, 115, 22, 0.25)',
-
- blueBright500: '#009FF9',
-
- blueRibbon: '#484CF6',
-
- caribbeanGreen: '#27DCB7',
-
- darkGrey: '#333333',
-
- electricViolet: '#DD0FFF',
-
- flamenco: '#FF800B',
-
- gold: '#FFD700',
-
- greenBright500: '#27EE76',
-
- grey50: '#B8B8B8',
- grey100: '#F7F7F7',
- grey200: '#EFEFF0',
- grey300: '#AEAEAE',
- grey350: '#828282',
- grey400: '#666666',
- grey500: '#747A92',
- grey600: '#999999',
- grey700: '#5A5E6C',
- grey800: '#54596F',
- grey900: '#2C2E37',
- lightGrey: '#E2E2E2',
- dividerGrey: '#2E2E2E',
-
- matchaGray900: '#2B2B2B',
-
- havelockBlue: '#0C93E5',
-
- jazzberryJam: '#D23E72',
-
- lividBrown: '#421B27',
-
- malachite: '#14D111',
-
- offWhite: '#F9FAFC',
-
- warning: '#FFE5C7',
-
- critical500: '#EF4444',
- critical950: '#450A0A',
- criticalBorder: 'rgba(239, 68, 68, 0.25)',
-
- persianRose: '#FF2DB7',
-
- purple500: '#B556FF',
-
- purpleHeart: '#3E42E5',
-
- red200: '#F59CA2',
-
- red300: '#F97570',
- red400: '#FF6666',
- red500: '#E43B70',
- red500Transparent10: '#E43B701A',
- matchaRed500: '#EF4444',
- matchaRed950: '#450A0A',
- redBorder: 'rgba(239, 68, 68, 0.25)',
-
- solanaGreen: '#14F195',
- solanaPurple: '#9945FF',
-
- transparent: '#00000000',
- transparent10: '#FFFFFF1A',
-
- turquoise: '#2BD7E2',
-
- white: '#FFFFFF',
- bottomSheetBg: '#191919',
-}
-
-export const lightThemeColors = {
- ...palette,
- primary: palette.white,
- secondary: palette.grey300,
- primaryBackground: palette.grey200,
- secondaryBackground: palette.black750,
- primaryText: palette.black700,
- primaryIcon: palette.black700,
- secondaryIcon: palette.black300,
- secondaryText: palette.grey400,
- error: palette.red500,
- surface: palette.white,
- surfaceText: palette.grey700,
- surfaceSecondary: palette.grey100,
- surfaceSecondaryText: palette.black500,
- surfaceContrast: palette.white,
- surfaceContrastText: palette.white,
- plainInputBackground: palette.grey200,
- regularInputBackground: palette.offWhite,
- highlight: palette.blueBright500,
- testnet: palette.red500,
- transparent: palette.transparent,
- bottomSheetBg: palette.bottomSheetBg,
-}
-
-export const darkThemeColors = {
- ...palette,
- primary: palette.black900,
- secondary: palette.black600,
- primaryBackground: palette.black,
- secondaryBackground: palette.black850,
- primaryText: palette.white,
- primaryIcon: palette.black600,
- secondaryIcon: palette.black300,
- secondaryText: palette.grey400,
- error: palette.red500,
- surface: palette.black200,
- surfaceText: palette.white,
- surfaceSecondary: palette.black650,
- surfaceSecondaryText: palette.grey300,
- surfaceContrast: palette.white,
- surfaceContrastText: palette.black900,
- plainInputBackground: palette.black200,
- regularInputBackground: palette.black750,
- highlight: palette.blueBright500,
- testnet: palette.red500,
- transparent: palette.transparent,
-}
-
-export const theme = createTheme({
- colors: lightThemeColors,
- spacing: {
- n_xxxxl: -240,
- n_xxxl: -60,
- n_xxl: -48,
- n_xl: -32,
- n_lx: -28,
- n_l: -24,
- n_lm: -20,
- n_m: -16,
- n_ms: -12,
- n_s: -8,
- n_xs: -4,
- n_xxs: -2,
- n_xxxs: -1,
- none: 0,
- xxxs: 1,
- xxs: 2,
- xs: 4,
- sx: 6,
- s: 8,
- ms: 12,
- m: 16,
- lm: 20,
- l: 24,
- lx: 28,
- xl: 32,
- xxl: 48,
- xxxl: 60,
- xxxxl: 240,
- },
- borderRadii: {
- none: 0,
- s: 4,
- ms: 6,
- m: 8,
- lm: 10,
- l: 12,
- lx: 16,
- xl: 20,
- xxl: 35,
- round: 1000,
- },
- breakpoints: {
- smallPhone: 0,
- phone: 380,
- largePhone: 430,
- tablet: 768,
- },
- cardVariants: {
- regular: {
- padding: 'ms',
- borderRadius: 'ms',
- backgroundColor: 'surface',
- },
- elevated: {
- shadowColor: 'surface',
- borderRadius: 'm',
- shadowOffset: {
- width: 0,
- height: 9,
- },
- shadowOpacity: 0.3,
- shadowRadius: 6,
- elevation: 9,
- },
- modal: {
- backgroundColor: 'surface',
- borderRadius: 'xl',
- },
- },
- textVariants: {
- ...textVariants,
-
- body0Medium: { ...textVariants.body0, ...textVariants.medium },
- body0Bold: { ...textVariants.body0, ...textVariants.bold },
-
- body1Medium: { ...textVariants.body1, ...textVariants.medium },
- body1Bold: { ...textVariants.body1, ...textVariants.bold },
-
- body2Medium: { ...textVariants.body2, ...textVariants.medium },
- body2Bold: { ...textVariants.body2, ...textVariants.bold },
-
- body3Medium: { ...textVariants.body3, ...textVariants.medium },
- body3Bold: { ...textVariants.body3, ...textVariants.bold },
-
- h1Medium: { ...textVariants.h1, ...textVariants.medium },
- h1Bold: { ...textVariants.h1, ...textVariants.bold },
-
- h2Medium: { ...textVariants.h2, ...textVariants.medium },
- h2Bold: { ...textVariants.h2, ...textVariants.bold },
-
- h3Medium: { ...textVariants.h3, ...textVariants.medium },
- h3Bold: { ...textVariants.h3, ...textVariants.bold },
-
- h4Medium: { ...textVariants.h4, ...textVariants.medium },
- h4Bold: { ...textVariants.h4, ...textVariants.bold },
- },
- inputVariants: {
- plain: {
- color: 'primaryText',
- fontSize: 19,
- paddingBottom: 'm',
- paddingTop: 'm',
- paddingHorizontal: 'xl',
- backgroundColor: 'plainInputBackground',
- },
- regular: {
- color: 'primaryText',
- fontSize: 19,
- padding: 'm',
- backgroundColor: 'regularInputBackground',
- borderRadius: 'lm',
- },
- transparent: {
- color: 'primaryText',
- fontSize: 19,
- padding: 'm',
- backgroundColor: 'transparent',
- borderRadius: 'lm',
- },
- underline: {
- fontSize: textVariants.h1.fontSize,
- color: 'purple500',
- borderBottomColor: 'purple500',
- borderBottomWidth: 2,
- paddingBottom: 'xs',
- },
- thickBlur: {
- padding: 'm',
- borderRadius: 'xl',
- backgroundColor: 'transparent10',
- },
- thickDark: {
- padding: 'm',
- borderRadius: 'xl',
- backgroundColor: 'surfaceSecondary',
- },
- transparentSmall: {
- color: 'primaryText',
- fontSize: 16,
- padding: 's',
- paddingHorizontal: 'm',
- backgroundColor: 'transparent',
- },
- },
-})
-
-export type Theme = typeof theme
-export type TextVariant = keyof Theme['textVariants']
-export type Spacing = keyof Theme['spacing']
-export type Color = keyof Theme['colors']
-export type BorderRadii = keyof Theme['borderRadii']
-export type FontWeight =
- | '500'
- | 'bold'
- | 'normal'
- | '100'
- | '200'
- | '300'
- | '400'
- | '600'
- | '700'
- | '800'
- | '900'
diff --git a/src/types/balance.ts b/src/types/balance.ts
index 92975fd08..5124871c4 100644
--- a/src/types/balance.ts
+++ b/src/types/balance.ts
@@ -32,4 +32,5 @@ export type BalanceInfo = {
formattedMobileValue: string
formattedSolValue: string
formattedTotal: string
+ total: number
}
diff --git a/src/utils/Balance.tsx b/src/utils/Balance.tsx
index 3eae2bf39..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'
@@ -35,7 +35,6 @@ import { humanReadable } from './solanaUtils'
import { useBalanceHistory } from './useBalanceHistory'
import { usePollTokenPrices } from './usePollTokenPrices'
-export const ORACLE_POLL_INTERVAL = 1000 * 15 * 60 // 15 minutes
const useBalanceHook = () => {
const { currentAccount } = useAccountStorage()
const { cluster, anchorProvider } = useSolana()
@@ -175,6 +174,8 @@ const useBalanceHook = () => {
solValue + hntValue + mobileValue + iotValue,
)
+ const total = solValue + hntValue + mobileValue + iotValue
+
return {
atas,
formattedDcValue,
@@ -183,6 +184,7 @@ const useBalanceHook = () => {
formattedMobileValue,
formattedSolValue,
formattedTotal,
+ total,
}
}, [
allBalances,
@@ -238,6 +240,7 @@ const initialState = {
formattedMobileValue: '',
formattedSolValue: '',
formattedTotal: undefined,
+ total: undefined,
networkTokensToDc: () => undefined,
oracleDateTime: undefined,
oraclePrice: undefined,
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/betterDebounce.ts b/src/utils/betterDebounce.ts
new file mode 100644
index 000000000..cf0df7508
--- /dev/null
+++ b/src/utils/betterDebounce.ts
@@ -0,0 +1,7 @@
+import { debounce as lodashDebounce } from 'lodash'
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const debounce = (func: any) => {
+ if (!func) return undefined
+ return lodashDebounce(func, 500, { leading: true, trailing: true })
+}
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 0f3837df8..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()
@@ -17,6 +17,7 @@ export const usesMetricSystem = RNLocalize.usesMetricSystem()
let phoneLang = 'en'
let phoneLocale = 'en-US'
+
if (Array.isArray(locales)) {
phoneLang = locales[0].languageCode
phoneLocale = locales[0].languageTag
diff --git a/src/utils/linking.ts b/src/utils/linking.ts
index b8555f912..5b6586001 100644
--- a/src/utils/linking.ts
+++ b/src/utils/linking.ts
@@ -5,9 +5,10 @@ import BN from 'bn.js'
import * as Linking from 'expo-linking'
import qs from 'qs'
import queryString from 'query-string'
-import { BurnRouteParam, PaymentRouteParam } from '../features/home/homeTypes'
-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('')
@@ -29,7 +30,7 @@ export const authenticatedLinking: LinkingOptions = {
PaymentScreen: 'payment',
DappLoginScreen: 'dapp_login',
ImportPrivateKey: 'import_key/:key',
- TabBarNavigator: {
+ ServiceSheetNavigator: {
screens: {
Governance: {
screens: {
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 77%
rename from src/components/map/utils.ts
rename to src/utils/mapUtils.ts
index 3a0a4741e..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,
}
@@ -34,5 +37,5 @@ export const MAP_CONTAINER_STYLE: ViewProps['style'] = {
width: '100%',
overflow: 'hidden',
position: 'relative',
- backgroundColor: 'rgb(19,24,37)',
+ backgroundColor: 'rgb(0,0,0)',
}
diff --git a/src/utils/parseMarkup.tsx b/src/utils/parseMarkup.tsx
index 540b21957..513407334 100644
--- a/src/utils/parseMarkup.tsx
+++ b/src/utils/parseMarkup.tsx
@@ -15,18 +15,18 @@ import Bullet from '@components/Bullet'
import * as Logger from './logger'
const symbols: Record = {
- b: ,
- light: ,
- blue: ,
- green: ,
- purple: ,
- red: ,
- orange: ,
- gray: ,
- center: ,
+ b: ,
+ light: ,
+ blue: ,
+ green: ,
+ purple: ,
+ red: ,
+ orange: ,
+ gray: ,
+ center: ,
a: ,
bullet: ,
- default: ,
+ default: ,
}
const parseMarkup = (
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 116f73382..88cb94a30 100644
--- a/src/utils/solanaUtils.ts
+++ b/src/utils/solanaUtils.ts
@@ -111,7 +111,13 @@ import { withPriorityFees } from '@utils/priorityFees'
import axios from 'axios'
import bs58 from 'bs58'
import Config from 'react-native-config'
-import { getSessionKey } from '../storage/secureStorage'
+import {
+ Metaplex,
+ Signer,
+ token,
+ walletAdapterIdentity,
+} from '@metaplex-foundation/js'
+import { getSessionKey } from '@config/storage/secureStorage'
import { Activity, Payment } from '../types/activity'
import {
Collectable,
@@ -508,45 +514,52 @@ export const createTransferCollectableMessage = async (
export const transferCollectable = async (
anchorProvider: AnchorProvider,
solanaAddress: string,
- heliumAddress: string,
- collectable: Collectable,
+ collectable: CompressedNFT,
payee: string,
): Promise => {
const payer = new PublicKey(solanaAddress)
try {
- const recipientPubKey = new PublicKey(payee)
- const mintPubkey = new PublicKey(collectable.address)
+ const feePayer: Signer = {
+ publicKey: anchorProvider.publicKey,
+ signTransaction: async (tx) => {
+ return anchorProvider.wallet.signTransaction(tx)
+ },
+ signMessage: async (msg) => msg,
+ signAllTransactions: async (txs) => {
+ return anchorProvider.wallet.signAllTransactions(txs)
+ },
+ }
- const instructions: TransactionInstruction[] = []
+ const asset = new PublicKey(collectable.id)
- const ownerATA = await getAssociatedTokenAddress(mintPubkey, payer)
+ const metaplex = new Metaplex(anchorProvider.connection)
+ metaplex.use(walletAdapterIdentity(anchorProvider.wallet))
+ const recipientPubKey = new PublicKey(payee)
+
+ const ownerATA = await getAssociatedTokenAddress(asset, payer)
const recipientATA = await getAssociatedTokenAddress(
- mintPubkey,
+ asset,
recipientPubKey,
true,
)
- instructions.push(
- createAssociatedTokenAccountIdempotentInstruction(
- anchorProvider.publicKey,
- recipientATA,
- recipientPubKey,
- mintPubkey,
- ),
- )
+ const nft = await metaplex.nfts().findByMint({ mintAddress: asset })
+
+ const txBuilder = metaplex
+ .nfts()
+ .builders()
+ .transfer({
+ nftOrSft: nft,
+ fromOwner: anchorProvider.publicKey,
+ toOwner: new PublicKey(payee),
+ amount: token(1),
+ authority: feePayer,
+ fromToken: ownerATA,
+ toToken: recipientATA,
+ })
- instructions.push(
- createTransferCheckedInstruction(
- ownerATA, // from (should be a token account)
- mintPubkey, // mint
- recipientATA, // to (should be a token account)
- payer, // from's owner
- 1, // amount
- 0, // decimals
- [], // signers
- ),
- )
+ const instructions = txBuilder.getInstructions()
return {
instructions: await withPriorityFees({
@@ -749,7 +762,6 @@ const mapProof = (assetProof: { proof: string[] }): AccountMeta[] => {
export const transferCompressedCollectable = async (
anchorProvider: AnchorProvider,
solanaAddress: string,
- heliumAddress: string,
collectable: CompressedNFT,
payee: string,
): Promise => {
@@ -830,6 +842,10 @@ export const transferCompressedCollectable = async (
}
export const heliumNFTs = (): string[] => {
+ return []
+}
+
+export const governanceNFTs = (): string[] => {
// HST collection ID
const fanoutMint = membershipCollectionKey(
fanoutKey('HST')[0],
@@ -904,28 +920,22 @@ export const heliumNFTs = (): string[] => {
export const getNFTs = async (
pubKey: PublicKey,
connection: WrappedConnection,
+ page = 1,
) => {
- const approvedNFTs = heliumNFTs()
-
const { items } = await connection.getAssetsByOwner<{
items: CompressedNFT[]
}>(
pubKey.toBase58(),
{ sortBy: 'created', sortDirection: 'asc' },
- 1000,
- 1,
+ 50,
+ page,
'',
'',
- { showFungible: true },
+ // TODO: Update helium-program-library to support new options
+ { showFungible: true, showCollectionMetadata: true } as any,
)
- return items.filter((item) => {
- const collection = item.grouping.find(
- (k) => k.group_key === 'collection',
- )?.group_value
-
- return approvedNFTs.includes(collection || '')
- })
+ return items
}
export const getHotspotWithRewards = async (
@@ -980,28 +990,6 @@ export const getCompressedCollectablesByCreator = async (
}
}
-/**
- * Returns the account's collectables with metadata
- * @param collectables collectables without metadata
- * @returns collectables with metadata
- */
-export const getNFTsMetadata = async (collectables: CompressedNFT[]) =>
- (
- await Promise.all(
- collectables.map(async (col) => {
- try {
- const { data } = await axios.get(col.content.json_uri, {
- timeout: 3000,
- })
-
- return { ...col, json: data }
- } catch (e: any) {
- return null
- }
- }),
- )
- ).filter(truthy)
-
/**
* Returns the account's collectables grouped by token type
* @param collectables collectables
@@ -1025,29 +1013,6 @@ export const groupNFTs = (collectables: CompressedNFT[]) => {
return collectablesGroupedByName
}
-/**
- * Returns the account's collectables grouped by token type
- * @param collectables collectables with metadata
- * @returns grouped collecables by token type
- */
-export const groupNFTsWithMetaData = (collectables: CompressedNFT[]) => {
- const collectablesGroupedByName = collectables.reduce((acc, cur) => {
- const { symbol } = cur.content.metadata
- const collection = cur.grouping.find(
- (k) => k.group_key === 'collection',
- )?.group_value
-
- if (!acc[collection || symbol]) {
- acc[collection || symbol] = [cur]
- } else {
- acc[collection || symbol].push(cur)
- }
- return acc
- }, {} as Record)
-
- return collectablesGroupedByName
-}
-
export const getHotspotPendingRewards = async (
provider: AnchorProvider,
hotspots: CompressedNFT[],
@@ -2071,3 +2036,13 @@ export const createUpdateCompressionDestinationTxn = async (
feePayer: payer,
}
}
+
+const sortValues: Record = {
+ [HNT_MINT.toBase58()]: 10,
+ [IOT_MINT.toBase58()]: 9,
+ [MOBILE_MINT.toBase58()]: 8,
+ [DC_MINT.toBase58()]: 7,
+}
+export function getSortValue(mint: string): number {
+ return sortValues[mint] || 0
+}
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 f088854d2..98139a039 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -42,13 +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/*"],
- "@types/*": ["./src/types/*"]
+ "@config/*": ["./src/config/*"],
+ "@types/*": ["./src/types/*"],
+ "@features/*": ["./src/features/*"],
+ "@services/*": ["src/app/services/*"],
+ "@store/*": ["./src/store/*"],
+ "@app/*": ["./src/app/*"]
}
},
"exclude": [
diff --git a/yarn.lock b/yarn.lock
index 031585792..0f0b60b39 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"
@@ -1697,6 +1867,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.25.0":
+ version: 7.25.7
+ resolution: "@babel/runtime@npm:7.25.7"
+ dependencies:
+ regenerator-runtime: ^0.14.0
+ checksum: 1d6133ed1cf1de1533cfe84a4a8f94525271a0d93f6af4f2cdae14884ec3c8a7148664ddf7fd2a14f82cc4485904a1761821a55875ad241c8b4034e95e7134b2
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.0.0, @babel/template@npm:^7.20.7, @babel/template@npm:^7.22.15, @babel/template@npm:^7.22.5, @babel/template@npm:^7.25.0, @babel/template@npm:^7.3.3":
version: 7.25.0
resolution: "@babel/template@npm:7.25.0"
@@ -1708,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"
@@ -1734,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"
@@ -1769,6 +1984,35 @@ __metadata:
languageName: node
linkType: hard
+"@bundlr-network/client@npm:^0.8.8":
+ version: 0.8.9
+ resolution: "@bundlr-network/client@npm:0.8.9"
+ dependencies:
+ "@solana/wallet-adapter-base": ^0.9.2
+ "@solana/web3.js": ^1.36.0
+ "@supercharge/promise-pool": ^2.1.0
+ algosdk: ^1.13.1
+ arbundles: ^0.6.21
+ arweave: ^1.11.4
+ async-retry: ^1.3.3
+ axios: ^0.25.0
+ base64url: ^3.0.1
+ bignumber.js: ^9.0.1
+ bs58: ^4.0.1
+ commander: ^8.2.0
+ csv: ^6.0.5
+ ethers: ^5.5.1
+ inquirer: ^8.2.0
+ js-sha256: ^0.9.0
+ mime-types: ^2.1.34
+ near-api-js: ^0.44.2
+ near-seed-phrase: ^0.2.0
+ bin:
+ bundlr: build/node/cli.js
+ checksum: 08f9c0c594a8f7a2bb57e721e9c4a5b2f803f74ed99dcfeb8f1744c6c3faef02ef834ad9ba5b62661bd13f85e7a344cb38994466af11c8bb4fae64389f7718ca
+ languageName: node
+ linkType: hard
+
"@coral-xyz/anchor@npm:^0.28.0":
version: 0.28.0
resolution: "@coral-xyz/anchor@npm:0.28.0"
@@ -1871,6 +2115,15 @@ __metadata:
languageName: node
linkType: hard
+"@ethereumjs/rlp@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "@ethereumjs/rlp@npm:4.0.1"
+ bin:
+ rlp: bin/rlp
+ checksum: 30db19c78faa2b6ff27275ab767646929207bb207f903f09eb3e4c273ce2738b45f3c82169ddacd67468b4f063d8d96035f2bf36f02b6b7e4d928eefe2e3ecbc
+ languageName: node
+ linkType: hard
+
"@ethereumjs/rlp@npm:^5.0.2":
version: 5.0.2
resolution: "@ethereumjs/rlp@npm:5.0.2"
@@ -1880,6 +2133,17 @@ __metadata:
languageName: node
linkType: hard
+"@ethereumjs/util@npm:^8.1.0":
+ version: 8.1.0
+ resolution: "@ethereumjs/util@npm:8.1.0"
+ dependencies:
+ "@ethereumjs/rlp": ^4.0.1
+ ethereum-cryptography: ^2.0.0
+ micro-ftch: ^0.3.1
+ checksum: 9ae5dee8f12b0faf81cd83f06a41560e79b0ba96a48262771d897a510ecae605eb6d84f687da001ab8ccffd50f612ae50f988ef76e6312c752897f462f3ac08d
+ languageName: node
+ linkType: hard
+
"@ethereumjs/util@npm:^9.0.3":
version: 9.1.0
resolution: "@ethereumjs/util@npm:9.1.0"
@@ -1890,552 +2154,1576 @@ __metadata:
languageName: node
linkType: hard
-"@ethersproject/bytes@npm:^5.7.0":
+"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.7.0":
version: 5.7.0
- resolution: "@ethersproject/bytes@npm:5.7.0"
+ resolution: "@ethersproject/abi@npm:5.7.0"
dependencies:
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/hash": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
"@ethersproject/logger": ^5.7.0
- checksum: 66ad365ceaab5da1b23b72225c71dce472cf37737af5118181fa8ab7447d696bea15ca22e3a0e8836fdd8cfac161afe321a7c67d0dde96f9f645ddd759676621
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ checksum: bc6962bb6cb854e4d2a4d65b2c49c716477675b131b1363312234bdbb7e19badb7d9ce66f4ca2a70ae2ea84f7123dbc4e300a1bfe5d58864a7eafabc1466627e
languageName: node
linkType: hard
-"@ethersproject/logger@npm:^5.7.0":
+"@ethersproject/abstract-provider@npm:5.7.0, @ethersproject/abstract-provider@npm:^5.7.0":
version: 5.7.0
- resolution: "@ethersproject/logger@npm:5.7.0"
- checksum: 075ab2f605f1fd0813f2e39c3308f77b44a67732b36e712d9bc085f22a84aac4da4f71b39bee50fe78da3e1c812673fadc41180c9970fe5e486e91ea17befe0d
+ resolution: "@ethersproject/abstract-provider@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/networks": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ "@ethersproject/web": ^5.7.0
+ checksum: 74cf4696245cf03bb7cc5b6cbf7b4b89dd9a79a1c4688126d214153a938126d4972d42c93182198653ce1de35f2a2cad68be40337d4774b3698a39b28f0228a8
languageName: node
linkType: hard
-"@ethersproject/sha2@npm:^5.7.0":
+"@ethersproject/abstract-signer@npm:5.7.0, @ethersproject/abstract-signer@npm:^5.7.0":
version: 5.7.0
- resolution: "@ethersproject/sha2@npm:5.7.0"
+ resolution: "@ethersproject/abstract-signer@npm:5.7.0"
dependencies:
+ "@ethersproject/abstract-provider": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
"@ethersproject/bytes": ^5.7.0
"@ethersproject/logger": ^5.7.0
- hash.js: 1.1.7
- checksum: 09321057c022effbff4cc2d9b9558228690b5dd916329d75c4b1ffe32ba3d24b480a367a7cc92d0f0c0b1c896814d03351ae4630e2f1f7160be2bcfbde435dbc
+ "@ethersproject/properties": ^5.7.0
+ checksum: a823dac9cfb761e009851050ebebd5b229d1b1cc4a75b125c2da130ff37e8218208f7f9d1386f77407705b889b23d4a230ad67185f8872f083143e0073cbfbe3
languageName: node
linkType: hard
-"@expo/bunyan@npm:^4.0.0":
- version: 4.0.0
- resolution: "@expo/bunyan@npm:4.0.0"
+"@ethersproject/address@npm:5.7.0, @ethersproject/address@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/address@npm:5.7.0"
dependencies:
- mv: ~2
- safe-json-stringify: ~1
- uuid: ^8.0.0
- dependenciesMeta:
- mv:
- optional: true
- safe-json-stringify:
- optional: true
- checksum: dce0b66fde1c11f987bc31b9afd9b714c4295ba750780ee8861ab8a912b37a2b9dd2ab9c9fbf3a85f3adbe66c6cd85e45bc76fa37c98ee23a7db3ad24601c296
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/rlp": ^5.7.0
+ checksum: 64ea5ebea9cc0e845c413e6cb1e54e157dd9fc0dffb98e239d3a3efc8177f2ff798cd4e3206cf3660ee8faeb7bef1a47dc0ebef0d7b132c32e61e550c7d4c843
languageName: node
linkType: hard
-"@expo/cli@npm:0.18.26":
- version: 0.18.26
- resolution: "@expo/cli@npm:0.18.26"
+"@ethersproject/base64@npm:5.7.0, @ethersproject/base64@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/base64@npm:5.7.0"
dependencies:
- "@babel/runtime": ^7.20.0
- "@expo/code-signing-certificates": 0.0.5
- "@expo/config": ~9.0.0-beta.0
- "@expo/config-plugins": ~8.0.8
- "@expo/devcert": ^1.0.0
- "@expo/env": ~0.3.0
- "@expo/image-utils": ^0.5.0
- "@expo/json-file": ^8.3.0
- "@expo/metro-config": ~0.18.6
- "@expo/osascript": ^2.0.31
- "@expo/package-manager": ^1.5.0
- "@expo/plist": ^0.1.0
- "@expo/prebuild-config": 7.0.8
- "@expo/rudder-sdk-node": 1.1.1
- "@expo/spawn-async": ^1.7.2
- "@expo/xcpretty": ^4.3.0
- "@react-native/dev-middleware": 0.74.85
- "@urql/core": 2.3.6
- "@urql/exchange-retry": 0.3.0
- accepts: ^1.3.8
- arg: 5.0.2
- better-opn: ~3.0.2
- bplist-creator: 0.0.7
- bplist-parser: ^0.3.1
- cacache: ^18.0.2
- chalk: ^4.0.0
- ci-info: ^3.3.0
- connect: ^3.7.0
- debug: ^4.3.4
- env-editor: ^0.4.1
- fast-glob: ^3.3.2
- find-yarn-workspace-root: ~2.0.0
- form-data: ^3.0.1
- freeport-async: 2.0.0
- fs-extra: ~8.1.0
- getenv: ^1.0.0
- glob: ^7.1.7
- graphql: 15.8.0
- graphql-tag: ^2.10.1
- https-proxy-agent: ^5.0.1
- internal-ip: 4.3.0
- is-docker: ^2.0.0
- is-wsl: ^2.1.1
- js-yaml: ^3.13.1
- json-schema-deref-sync: ^0.13.0
- lodash.debounce: ^4.0.8
- md5hex: ^1.0.0
- minimatch: ^3.0.4
- node-fetch: ^2.6.7
- node-forge: ^1.3.1
- npm-package-arg: ^7.0.0
- open: ^8.3.0
- ora: 3.4.0
- picomatch: ^3.0.1
- pretty-bytes: 5.6.0
- progress: 2.0.3
- prompts: ^2.3.2
- qrcode-terminal: 0.11.0
- require-from-string: ^2.0.2
- requireg: ^0.2.2
- resolve: ^1.22.2
- resolve-from: ^5.0.0
- resolve.exports: ^2.0.2
- semver: ^7.6.0
- send: ^0.18.0
- slugify: ^1.3.4
- source-map-support: ~0.5.21
- stacktrace-parser: ^0.1.10
- structured-headers: ^0.4.1
- tar: ^6.0.5
- temp-dir: ^2.0.0
- tempy: ^0.7.1
- terminal-link: ^2.1.1
- text-table: ^0.2.0
- url-join: 4.0.0
- wrap-ansi: ^7.0.0
- ws: ^8.12.1
- bin:
- expo-internal: build/bin/cli
- checksum: be85e3ed9614d212ca4ffe49d482371e86fc0dc0df018c41dd1b8e26e61977afcc33391c86ccec9dc356240c5673e6723fd995318cf709d843a8d6f06061bed8
+ "@ethersproject/bytes": ^5.7.0
+ checksum: 7dd5d734d623582f08f665434f53685041a3d3b334a0e96c0c8afa8bbcaab934d50e5b6b980e826a8fde8d353e0b18f11e61faf17468177274b8e7c69cd9742b
languageName: node
linkType: hard
-"@expo/code-signing-certificates@npm:0.0.5":
- version: 0.0.5
- resolution: "@expo/code-signing-certificates@npm:0.0.5"
+"@ethersproject/basex@npm:5.7.0, @ethersproject/basex@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/basex@npm:5.7.0"
dependencies:
- node-forge: ^1.2.1
- nullthrows: ^1.1.1
- checksum: 4a1c73a6bc74443284a45db698ede874c7d47f6ed58cf44adaa255139490c8754d81dc1556247f3782cdc5034382fb72f23b0033daa2117facad4eb13b841e37
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ checksum: 326087b7e1f3787b5fe6cd1cf2b4b5abfafbc355a45e88e22e5e9d6c845b613ffc5301d629b28d5c4d5e2bfe9ec424e6782c804956dff79be05f0098cb5817de
languageName: node
linkType: hard
-"@expo/config-plugins@npm:8.0.8, @expo/config-plugins@npm:~8.0.0-beta.0, @expo/config-plugins@npm:~8.0.8":
- version: 8.0.8
- resolution: "@expo/config-plugins@npm:8.0.8"
+"@ethersproject/bignumber@npm:5.7.0, @ethersproject/bignumber@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/bignumber@npm:5.7.0"
dependencies:
- "@expo/config-types": ^51.0.0-unreleased
- "@expo/json-file": ~8.3.0
- "@expo/plist": ^0.1.0
- "@expo/sdk-runtime-versions": ^1.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.5.4
- slash: ^3.0.0
- slugify: ^1.6.6
- xcode: ^3.0.1
- xml2js: 0.6.0
- checksum: 2b46a636b7aee46825f17b5208de735c98dca70938a5821e00172e5cebaa347f4a4537b2d94fefef7c8d2f5a979e4f8d4b4d0775a559c7d7dec09c78e2d93bae
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ bn.js: ^5.2.1
+ checksum: 8c9a134b76f3feb4ec26a5a27379efb4e156b8fb2de0678a67788a91c7f4e30abe9d948638458e4b20f2e42380da0adacc7c9389d05fce070692edc6ae9b4904
languageName: node
linkType: hard
-"@expo/config-plugins@npm:^4.0.3":
- version: 4.1.5
- resolution: "@expo/config-plugins@npm:4.1.5"
+"@ethersproject/bytes@npm:5.7.0, @ethersproject/bytes@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/bytes@npm:5.7.0"
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
+ "@ethersproject/logger": ^5.7.0
+ checksum: 66ad365ceaab5da1b23b72225c71dce472cf37737af5118181fa8ab7447d696bea15ca22e3a0e8836fdd8cfac161afe321a7c67d0dde96f9f645ddd759676621
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
+"@ethersproject/constants@npm:5.7.0, @ethersproject/constants@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/constants@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bignumber": ^5.7.0
+ checksum: 6d4b1355747cce837b3e76ec3bde70e4732736f23b04f196f706ebfa5d4d9c2be50904a390d4d40ce77803b98d03d16a9b6898418e04ba63491933ce08c4ba8a
languageName: node
linkType: hard
-"@expo/config-types@npm:^51.0.0-unreleased":
- version: 51.0.2
- resolution: "@expo/config-types@npm:51.0.2"
- checksum: 33b4397df1c85c784f5251a3ea4e1d960c44470aef13925502f8f527680d5ec2b341ecffbaf5c7f5ab3a1a89cdb68d496f54323a73910dfe0a37cb86ae6dc717
+"@ethersproject/contracts@npm:5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/contracts@npm:5.7.0"
+ dependencies:
+ "@ethersproject/abi": ^5.7.0
+ "@ethersproject/abstract-provider": ^5.7.0
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ checksum: 6ccf1121cba01b31e02f8c507cb971ab6bfed85706484a9ec09878ef1594a62215f43c4fdef8f4a4875b99c4a800bc95e3be69b1803f8ce479e07634b5a740c0
languageName: node
linkType: hard
-"@expo/config@npm:9.0.3, @expo/config@npm:~9.0.0, @expo/config@npm:~9.0.0-beta.0":
- version: 9.0.3
- resolution: "@expo/config@npm:9.0.3"
+"@ethersproject/hash@npm:5.7.0, @ethersproject/hash@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/hash@npm:5.7.0"
dependencies:
- "@babel/code-frame": ~7.10.4
- "@expo/config-plugins": ~8.0.8
- "@expo/config-types": ^51.0.0-unreleased
- "@expo/json-file": ^8.3.0
- getenv: ^1.0.0
- glob: 7.1.6
- require-from-string: ^2.0.2
- resolve-from: ^5.0.0
- semver: ^7.6.0
- slugify: ^1.3.4
- sucrase: 3.34.0
- checksum: 884d9693f5021b6d29009aa9d0e698fd9aa2ae90e25a71d5709943f0af8620a4e28b2a1da425a2f6f52d340bfc5a52e06328487851187fd165aacafcd9247aed
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/base64": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ checksum: 6e9fa8d14eb08171cd32f17f98cc108ec2aeca74a427655f0d689c550fee0b22a83b3b400fad7fb3f41cf14d4111f87f170aa7905bcbcd1173a55f21b06262ef
languageName: node
linkType: hard
-"@expo/devcert@npm:^1.0.0":
- version: 1.1.0
- resolution: "@expo/devcert@npm:1.1.0"
+"@ethersproject/hdnode@npm:5.7.0, @ethersproject/hdnode@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/hdnode@npm:5.7.0"
dependencies:
- application-config-path: ^0.1.0
- command-exists: ^1.2.4
- debug: ^3.1.0
- eol: ^0.9.1
- get-port: ^3.2.0
- glob: ^7.1.2
- lodash: ^4.17.4
- mkdirp: ^0.5.1
- password-prompt: ^1.0.4
- rimraf: ^2.6.2
- sudo-prompt: ^8.2.0
- tmp: ^0.0.33
- tslib: ^2.4.0
- checksum: bb99996d7fc31c5269afbd9ab43066090ea986006d14c8c393165f813d90c21ff9fc40f16b247778a7026714c2a743ce6e8b0df25e135711e991fa0bbfb3555b
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/basex": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/pbkdf2": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/sha2": ^5.7.0
+ "@ethersproject/signing-key": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ "@ethersproject/wordlists": ^5.7.0
+ checksum: bfe5ca2d89a42de73655f853170ef4766b933c5f481cddad709b3aca18823275b096e572f92d1602a052f80b426edde44ad6b9d028799775a7dad4a5bbed2133
languageName: node
linkType: hard
-"@expo/env@npm:~0.3.0":
- version: 0.3.0
- resolution: "@expo/env@npm:0.3.0"
+"@ethersproject/json-wallets@npm:5.7.0, @ethersproject/json-wallets@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/json-wallets@npm:5.7.0"
+ dependencies:
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/hdnode": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/pbkdf2": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/random": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ aes-js: 3.0.0
+ scrypt-js: 3.0.1
+ checksum: f583458d22db62efaaf94d38dd243482776a45bf90f9f3882fbad5aa0b8fd288b41eb7c1ff8ec0b99c9b751088e43d6173530db64dd33c59f9d8daa8d7ad5aa2
+ languageName: node
+ linkType: hard
+
+"@ethersproject/keccak256@npm:5.7.0, @ethersproject/keccak256@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/keccak256@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ js-sha3: 0.8.0
+ checksum: ff70950d82203aab29ccda2553422cbac2e7a0c15c986bd20a69b13606ed8bb6e4fdd7b67b8d3b27d4f841e8222cbaccd33ed34be29f866fec7308f96ed244c6
+ languageName: node
+ linkType: hard
+
+"@ethersproject/logger@npm:5.7.0, @ethersproject/logger@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/logger@npm:5.7.0"
+ checksum: 075ab2f605f1fd0813f2e39c3308f77b44a67732b36e712d9bc085f22a84aac4da4f71b39bee50fe78da3e1c812673fadc41180c9970fe5e486e91ea17befe0d
+ languageName: node
+ linkType: hard
+
+"@ethersproject/networks@npm:5.7.1, @ethersproject/networks@npm:^5.7.0":
+ version: 5.7.1
+ resolution: "@ethersproject/networks@npm:5.7.1"
+ dependencies:
+ "@ethersproject/logger": ^5.7.0
+ checksum: 0339f312304c17d9a0adce550edb825d4d2c8c9468c1634c44172c67a9ed256f594da62c4cda5c3837a0f28b7fabc03aca9b492f68ff1fdad337ee861b27bd5d
+ languageName: node
+ linkType: hard
+
+"@ethersproject/pbkdf2@npm:5.7.0, @ethersproject/pbkdf2@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/pbkdf2@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/sha2": ^5.7.0
+ checksum: b895adb9e35a8a127e794f7aadc31a2424ef355a70e51cde10d457e3e888bb8102373199a540cf61f2d6b9a32e47358f9c65b47d559f42bf8e596b5fd67901e9
+ languageName: node
+ linkType: hard
+
+"@ethersproject/properties@npm:5.7.0, @ethersproject/properties@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/properties@npm:5.7.0"
+ dependencies:
+ "@ethersproject/logger": ^5.7.0
+ checksum: 6ab0ccf0c3aadc9221e0cdc5306ce6cd0df7f89f77d77bccdd1277182c9ead0202cd7521329ba3acde130820bf8af299e17cf567d0d497c736ee918207bbf59f
+ languageName: node
+ linkType: hard
+
+"@ethersproject/providers@npm:5.7.2":
+ version: 5.7.2
+ resolution: "@ethersproject/providers@npm:5.7.2"
+ dependencies:
+ "@ethersproject/abstract-provider": ^5.7.0
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/base64": ^5.7.0
+ "@ethersproject/basex": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/hash": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/networks": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/random": ^5.7.0
+ "@ethersproject/rlp": ^5.7.0
+ "@ethersproject/sha2": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ "@ethersproject/web": ^5.7.0
+ bech32: 1.1.4
+ ws: 7.4.6
+ checksum: 1754c731a5ca6782ae9677f4a9cd8b6246c4ef21a966c9a01b133750f3c578431ec43ec254e699969c4a0f87e84463ded50f96b415600aabd37d2056aee58c19
+ languageName: node
+ linkType: hard
+
+"@ethersproject/random@npm:5.7.0, @ethersproject/random@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/random@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ checksum: 017829c91cff6c76470852855108115b0b52c611b6be817ed1948d56ba42d6677803ec2012aa5ae298a7660024156a64c11fcf544e235e239ab3f89f0fff7345
+ languageName: node
+ linkType: hard
+
+"@ethersproject/rlp@npm:5.7.0, @ethersproject/rlp@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/rlp@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ checksum: bce165b0f7e68e4d091c9d3cf47b247cac33252df77a095ca4281d32d5eeaaa3695d9bc06b2b057c5015353a68df89f13a4a54a72e888e4beeabbe56b15dda6e
+ languageName: node
+ linkType: hard
+
+"@ethersproject/sha2@npm:5.7.0, @ethersproject/sha2@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/sha2@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ hash.js: 1.1.7
+ checksum: 09321057c022effbff4cc2d9b9558228690b5dd916329d75c4b1ffe32ba3d24b480a367a7cc92d0f0c0b1c896814d03351ae4630e2f1f7160be2bcfbde435dbc
+ languageName: node
+ linkType: hard
+
+"@ethersproject/signing-key@npm:5.7.0, @ethersproject/signing-key@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/signing-key@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ bn.js: ^5.2.1
+ elliptic: 6.5.4
+ hash.js: 1.1.7
+ checksum: 8f8de09b0aac709683bbb49339bc0a4cd2f95598f3546436c65d6f3c3a847ffa98e06d35e9ed2b17d8030bd2f02db9b7bd2e11c5cf8a71aad4537487ab4cf03a
+ languageName: node
+ linkType: hard
+
+"@ethersproject/solidity@npm:5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/solidity@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/sha2": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ checksum: 9a02f37f801c96068c3e7721f83719d060175bc4e80439fe060e92bd7acfcb6ac1330c7e71c49f4c2535ca1308f2acdcb01e00133129aac00581724c2d6293f3
+ languageName: node
+ linkType: hard
+
+"@ethersproject/strings@npm:5.7.0, @ethersproject/strings@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/strings@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ checksum: 5ff78693ae3fdf3cf23e1f6dc047a61e44c8197d2408c42719fef8cb7b7b3613a4eec88ac0ed1f9f5558c74fe0de7ae3195a29ca91a239c74b9f444d8e8b50df
+ languageName: node
+ linkType: hard
+
+"@ethersproject/transactions@npm:5.7.0, @ethersproject/transactions@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/transactions@npm:5.7.0"
+ dependencies:
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/rlp": ^5.7.0
+ "@ethersproject/signing-key": ^5.7.0
+ checksum: a31b71996d2b283f68486241bff0d3ea3f1ba0e8f1322a8fffc239ccc4f4a7eb2ea9994b8fd2f093283fd75f87bae68171e01b6265261f821369aca319884a79
+ languageName: node
+ linkType: hard
+
+"@ethersproject/units@npm:5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/units@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/constants": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ checksum: 304714f848cd32e57df31bf545f7ad35c2a72adae957198b28cbc62166daa929322a07bff6e9c9ac4577ab6aa0de0546b065ed1b2d20b19e25748b7d475cb0fc
+ languageName: node
+ linkType: hard
+
+"@ethersproject/wallet@npm:5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/wallet@npm:5.7.0"
+ dependencies:
+ "@ethersproject/abstract-provider": ^5.7.0
+ "@ethersproject/abstract-signer": ^5.7.0
+ "@ethersproject/address": ^5.7.0
+ "@ethersproject/bignumber": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/hash": ^5.7.0
+ "@ethersproject/hdnode": ^5.7.0
+ "@ethersproject/json-wallets": ^5.7.0
+ "@ethersproject/keccak256": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/random": ^5.7.0
+ "@ethersproject/signing-key": ^5.7.0
+ "@ethersproject/transactions": ^5.7.0
+ "@ethersproject/wordlists": ^5.7.0
+ checksum: a4009bf7331eddab38e3015b5e9101ef92de7f705b00a6196b997db0e5635b6d83561674d46c90c6f77b87c0500fe4a6b0183ba13749efc22db59c99deb82fbd
+ languageName: node
+ linkType: hard
+
+"@ethersproject/web@npm:5.7.1, @ethersproject/web@npm:^5.7.0":
+ version: 5.7.1
+ resolution: "@ethersproject/web@npm:5.7.1"
+ dependencies:
+ "@ethersproject/base64": ^5.7.0
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ checksum: 7028c47103f82fd2e2c197ce0eecfacaa9180ffeec7de7845b1f4f9b19d84081b7a48227aaddde05a4aaa526af574a9a0ce01cc0fc75e3e371f84b38b5b16b2b
+ languageName: node
+ linkType: hard
+
+"@ethersproject/wordlists@npm:5.7.0, @ethersproject/wordlists@npm:^5.7.0":
+ version: 5.7.0
+ resolution: "@ethersproject/wordlists@npm:5.7.0"
+ dependencies:
+ "@ethersproject/bytes": ^5.7.0
+ "@ethersproject/hash": ^5.7.0
+ "@ethersproject/logger": ^5.7.0
+ "@ethersproject/properties": ^5.7.0
+ "@ethersproject/strings": ^5.7.0
+ checksum: 30eb6eb0731f9ef5faa44bf9c0c6e950bcaaef61e4d2d9ce0ae6d341f4e2d6d1f4ab4f8880bfce03b7aac4b862fb740e1421170cfbf8e2aafc359277d49e6e97
+ languageName: node
+ linkType: hard
+
+"@expo/bunyan@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@expo/bunyan@npm:4.0.0"
+ dependencies:
+ mv: ~2
+ safe-json-stringify: ~1
+ uuid: ^8.0.0
+ dependenciesMeta:
+ mv:
+ optional: true
+ safe-json-stringify:
+ optional: true
+ checksum: dce0b66fde1c11f987bc31b9afd9b714c4295ba750780ee8861ab8a912b37a2b9dd2ab9c9fbf3a85f3adbe66c6cd85e45bc76fa37c98ee23a7db3ad24601c296
+ languageName: node
+ linkType: hard
+
+"@expo/cli@npm:0.18.26":
+ version: 0.18.26
+ resolution: "@expo/cli@npm:0.18.26"
dependencies:
+ "@babel/runtime": ^7.20.0
+ "@expo/code-signing-certificates": 0.0.5
+ "@expo/config": ~9.0.0-beta.0
+ "@expo/config-plugins": ~8.0.8
+ "@expo/devcert": ^1.0.0
+ "@expo/env": ~0.3.0
+ "@expo/image-utils": ^0.5.0
+ "@expo/json-file": ^8.3.0
+ "@expo/metro-config": ~0.18.6
+ "@expo/osascript": ^2.0.31
+ "@expo/package-manager": ^1.5.0
+ "@expo/plist": ^0.1.0
+ "@expo/prebuild-config": 7.0.8
+ "@expo/rudder-sdk-node": 1.1.1
+ "@expo/spawn-async": ^1.7.2
+ "@expo/xcpretty": ^4.3.0
+ "@react-native/dev-middleware": 0.74.85
+ "@urql/core": 2.3.6
+ "@urql/exchange-retry": 0.3.0
+ accepts: ^1.3.8
+ arg: 5.0.2
+ better-opn: ~3.0.2
+ bplist-creator: 0.0.7
+ bplist-parser: ^0.3.1
+ cacache: ^18.0.2
chalk: ^4.0.0
+ ci-info: ^3.3.0
+ connect: ^3.7.0
debug: ^4.3.4
- dotenv: ~16.4.5
- dotenv-expand: ~11.0.6
+ env-editor: ^0.4.1
+ fast-glob: ^3.3.2
+ find-yarn-workspace-root: ~2.0.0
+ form-data: ^3.0.1
+ freeport-async: 2.0.0
+ fs-extra: ~8.1.0
getenv: ^1.0.0
- checksum: 4199b7a3e186de81a5ddae4966d1a60694c1f0b3b24c190b9e5a584d47fb98254c8597ed66808511c09b3ee2774284fc72e03fc69ad9ee79005a7cd470ef6787
+ glob: ^7.1.7
+ graphql: 15.8.0
+ graphql-tag: ^2.10.1
+ https-proxy-agent: ^5.0.1
+ internal-ip: 4.3.0
+ is-docker: ^2.0.0
+ is-wsl: ^2.1.1
+ js-yaml: ^3.13.1
+ json-schema-deref-sync: ^0.13.0
+ lodash.debounce: ^4.0.8
+ md5hex: ^1.0.0
+ minimatch: ^3.0.4
+ node-fetch: ^2.6.7
+ node-forge: ^1.3.1
+ npm-package-arg: ^7.0.0
+ open: ^8.3.0
+ ora: 3.4.0
+ picomatch: ^3.0.1
+ pretty-bytes: 5.6.0
+ progress: 2.0.3
+ prompts: ^2.3.2
+ qrcode-terminal: 0.11.0
+ require-from-string: ^2.0.2
+ requireg: ^0.2.2
+ resolve: ^1.22.2
+ resolve-from: ^5.0.0
+ resolve.exports: ^2.0.2
+ semver: ^7.6.0
+ send: ^0.18.0
+ slugify: ^1.3.4
+ source-map-support: ~0.5.21
+ stacktrace-parser: ^0.1.10
+ structured-headers: ^0.4.1
+ tar: ^6.0.5
+ temp-dir: ^2.0.0
+ tempy: ^0.7.1
+ terminal-link: ^2.1.1
+ text-table: ^0.2.0
+ url-join: 4.0.0
+ wrap-ansi: ^7.0.0
+ ws: ^8.12.1
+ bin:
+ expo-internal: build/bin/cli
+ checksum: be85e3ed9614d212ca4ffe49d482371e86fc0dc0df018c41dd1b8e26e61977afcc33391c86ccec9dc356240c5673e6723fd995318cf709d843a8d6f06061bed8
+ languageName: node
+ linkType: hard
+
+"@expo/code-signing-certificates@npm:0.0.5":
+ version: 0.0.5
+ resolution: "@expo/code-signing-certificates@npm:0.0.5"
+ dependencies:
+ node-forge: ^1.2.1
+ nullthrows: ^1.1.1
+ checksum: 4a1c73a6bc74443284a45db698ede874c7d47f6ed58cf44adaa255139490c8754d81dc1556247f3782cdc5034382fb72f23b0033daa2117facad4eb13b841e37
+ languageName: node
+ linkType: hard
+
+"@expo/config-plugins@npm:8.0.8, @expo/config-plugins@npm:~8.0.0-beta.0, @expo/config-plugins@npm:~8.0.8":
+ version: 8.0.8
+ resolution: "@expo/config-plugins@npm:8.0.8"
+ dependencies:
+ "@expo/config-types": ^51.0.0-unreleased
+ "@expo/json-file": ~8.3.0
+ "@expo/plist": ^0.1.0
+ "@expo/sdk-runtime-versions": ^1.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.5.4
+ slash: ^3.0.0
+ slugify: ^1.6.6
+ xcode: ^3.0.1
+ xml2js: 0.6.0
+ checksum: 2b46a636b7aee46825f17b5208de735c98dca70938a5821e00172e5cebaa347f4a4537b2d94fefef7c8d2f5a979e4f8d4b4d0775a559c7d7dec09c78e2d93bae
+ languageName: node
+ linkType: hard
+
+"@expo/config-types@npm:^51.0.0-unreleased":
+ version: 51.0.2
+ resolution: "@expo/config-types@npm:51.0.2"
+ checksum: 33b4397df1c85c784f5251a3ea4e1d960c44470aef13925502f8f527680d5ec2b341ecffbaf5c7f5ab3a1a89cdb68d496f54323a73910dfe0a37cb86ae6dc717
+ languageName: node
+ linkType: hard
+
+"@expo/config@npm:9.0.3, @expo/config@npm:~9.0.0, @expo/config@npm:~9.0.0-beta.0":
+ version: 9.0.3
+ resolution: "@expo/config@npm:9.0.3"
+ dependencies:
+ "@babel/code-frame": ~7.10.4
+ "@expo/config-plugins": ~8.0.8
+ "@expo/config-types": ^51.0.0-unreleased
+ "@expo/json-file": ^8.3.0
+ getenv: ^1.0.0
+ glob: 7.1.6
+ require-from-string: ^2.0.2
+ resolve-from: ^5.0.0
+ semver: ^7.6.0
+ slugify: ^1.3.4
+ sucrase: 3.34.0
+ checksum: 884d9693f5021b6d29009aa9d0e698fd9aa2ae90e25a71d5709943f0af8620a4e28b2a1da425a2f6f52d340bfc5a52e06328487851187fd165aacafcd9247aed
+ languageName: node
+ linkType: hard
+
+"@expo/devcert@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "@expo/devcert@npm:1.1.0"
+ dependencies:
+ application-config-path: ^0.1.0
+ command-exists: ^1.2.4
+ debug: ^3.1.0
+ eol: ^0.9.1
+ get-port: ^3.2.0
+ glob: ^7.1.2
+ lodash: ^4.17.4
+ mkdirp: ^0.5.1
+ password-prompt: ^1.0.4
+ rimraf: ^2.6.2
+ sudo-prompt: ^8.2.0
+ tmp: ^0.0.33
+ tslib: ^2.4.0
+ checksum: bb99996d7fc31c5269afbd9ab43066090ea986006d14c8c393165f813d90c21ff9fc40f16b247778a7026714c2a743ce6e8b0df25e135711e991fa0bbfb3555b
+ languageName: node
+ linkType: hard
+
+"@expo/env@npm:~0.3.0":
+ version: 0.3.0
+ resolution: "@expo/env@npm:0.3.0"
+ dependencies:
+ chalk: ^4.0.0
+ debug: ^4.3.4
+ dotenv: ~16.4.5
+ dotenv-expand: ~11.0.6
+ getenv: ^1.0.0
+ checksum: 4199b7a3e186de81a5ddae4966d1a60694c1f0b3b24c190b9e5a584d47fb98254c8597ed66808511c09b3ee2774284fc72e03fc69ad9ee79005a7cd470ef6787
+ languageName: node
+ linkType: hard
+
+"@expo/image-utils@npm:^0.5.0":
+ version: 0.5.1
+ resolution: "@expo/image-utils@npm:0.5.1"
+ dependencies:
+ "@expo/spawn-async": ^1.7.2
+ chalk: ^4.0.0
+ fs-extra: 9.0.0
+ getenv: ^1.0.0
+ jimp-compact: 0.16.1
+ node-fetch: ^2.6.0
+ parse-png: ^2.1.0
+ resolve-from: ^5.0.0
+ semver: ^7.6.0
+ tempy: 0.3.0
+ checksum: ce369f863635391ce752832bba081b90130140de931166b9d2e26384087a8d04a3b401eacdfba874b09da1d18e90526328d82ebdc4798925c7fe0593dc08e4e6
+ 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"
+ dependencies:
+ "@babel/code-frame": ~7.10.4
+ json5: ^2.2.2
+ write-file-atomic: ^2.3.0
+ checksum: 49fcb3581ac21c1c223459f32e9e931149b56a7587318f666303a62e719e3d0f122ff56a60d47ee31fac937c297a66400a00fcee63a17bebbf4b8cd30c5138c1
+ languageName: node
+ linkType: hard
+
+"@expo/metro-config@npm:0.18.10, @expo/metro-config@npm:~0.18.6":
+ version: 0.18.10
+ resolution: "@expo/metro-config@npm:0.18.10"
+ dependencies:
+ "@babel/core": ^7.20.0
+ "@babel/generator": ^7.20.5
+ "@babel/parser": ^7.20.0
+ "@babel/types": ^7.20.0
+ "@expo/config": ~9.0.0-beta.0
+ "@expo/env": ~0.3.0
+ "@expo/json-file": ~8.3.0
+ "@expo/spawn-async": ^1.7.2
+ chalk: ^4.1.0
+ debug: ^4.3.2
+ find-yarn-workspace-root: ~2.0.0
+ fs-extra: ^9.1.0
+ getenv: ^1.0.0
+ glob: ^7.2.3
+ jsc-safe-url: ^0.2.4
+ lightningcss: ~1.19.0
+ postcss: ~8.4.32
+ resolve-from: ^5.0.0
+ checksum: d4292e925b58fd692477a122a6652e3f95eac8a7dca7319d7b14c03a6b3b7b6b7ebb26b263c31cdc085bc7f3460b7fa550538827915eab5ff0e60895e3527d73
+ languageName: node
+ linkType: hard
+
+"@expo/osascript@npm:^2.0.31":
+ version: 2.0.33
+ resolution: "@expo/osascript@npm:2.0.33"
+ dependencies:
+ "@expo/spawn-async": ^1.5.0
+ exec-async: ^2.2.0
+ checksum: f1ae2e365ec82fcfefbdcd3ceb52da1b38c54e55a2ceb884ca06fb9259544c032b2f8133b803be152e86d79b8510fda8320811053894884819fa10b66268045d
+ languageName: node
+ linkType: hard
+
+"@expo/package-manager@npm:^1.5.0":
+ version: 1.5.2
+ resolution: "@expo/package-manager@npm:1.5.2"
+ dependencies:
+ "@expo/json-file": ^8.3.0
+ "@expo/spawn-async": ^1.7.2
+ ansi-regex: ^5.0.0
+ chalk: ^4.0.0
+ find-up: ^5.0.0
+ find-yarn-workspace-root: ~2.0.0
+ js-yaml: ^3.13.1
+ micromatch: ^4.0.2
+ npm-package-arg: ^7.0.0
+ ora: ^3.4.0
+ split: ^1.0.1
+ sudo-prompt: 9.1.1
+ checksum: 825e727106592bac98c82c69bf316b8b1ee20829f7f3e909cf374861b771cfa77d38b029f8b078341b2a9333004b4b90392f6f1a6a366c45ecf3f397798fb2a4
+ languageName: node
+ linkType: hard
+
+"@expo/plist@npm:^0.1.0":
+ version: 0.1.3
+ resolution: "@expo/plist@npm:0.1.3"
+ dependencies:
+ "@xmldom/xmldom": ~0.7.7
+ base64-js: ^1.2.3
+ xmlbuilder: ^14.0.0
+ checksum: 8abe78bed4d1849f2cddddd1a238c6fe5c2549a9dee40158224ff70112f31503db3f17a522b6e21f16eea66b5f4b46cc49d22f2b369067d00a88ef6d301a50cd
+ languageName: node
+ linkType: hard
+
+"@expo/prebuild-config@npm:7.0.6":
+ version: 7.0.6
+ resolution: "@expo/prebuild-config@npm:7.0.6"
+ dependencies:
+ "@expo/config": ~9.0.0-beta.0
+ "@expo/config-plugins": ~8.0.0-beta.0
+ "@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.84
+ 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: 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
-"@expo/image-utils@npm:^0.5.0":
- version: 0.5.1
- resolution: "@expo/image-utils@npm:0.5.1"
+"@graphql-tools/executor-graphql-ws@npm:^1.3.1":
+ version: 1.3.1
+ resolution: "@graphql-tools/executor-graphql-ws@npm:1.3.1"
dependencies:
- "@expo/spawn-async": ^1.7.2
- chalk: ^4.0.0
- fs-extra: 9.0.0
- getenv: ^1.0.0
- jimp-compact: 0.16.1
- node-fetch: ^2.6.0
- parse-png: ^2.1.0
- resolve-from: ^5.0.0
- semver: ^7.6.0
- tempy: 0.3.0
- checksum: ce369f863635391ce752832bba081b90130140de931166b9d2e26384087a8d04a3b401eacdfba874b09da1d18e90526328d82ebdc4798925c7fe0593dc08e4e6
+ "@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
-"@expo/json-file@npm:8.2.36":
- version: 8.2.36
- resolution: "@expo/json-file@npm:8.2.36"
+"@graphql-tools/executor-http@npm:^1.1.8":
+ version: 1.1.8
+ resolution: "@graphql-tools/executor-http@npm:1.1.8"
dependencies:
- "@babel/code-frame": ~7.10.4
- json5: ^1.0.1
- write-file-atomic: ^2.3.0
- checksum: 37ce80b3472fef2a56136ebff5993d98ab4fbd45c4d7791ff47be80438dbeabd84bc699a401da0c314357ef65d8fff87a5a1241b3119db2d575878f9321bd1e7
+ "@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
-"@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"
+"@graphql-tools/executor-legacy-ws@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "@graphql-tools/executor-legacy-ws@npm:1.1.1"
dependencies:
- "@babel/code-frame": ~7.10.4
- json5: ^2.2.2
- write-file-atomic: ^2.3.0
- checksum: 49fcb3581ac21c1c223459f32e9e931149b56a7587318f666303a62e719e3d0f122ff56a60d47ee31fac937c297a66400a00fcee63a17bebbf4b8cd30c5138c1
+ "@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
-"@expo/metro-config@npm:0.18.10, @expo/metro-config@npm:~0.18.6":
- version: 0.18.10
- resolution: "@expo/metro-config@npm:0.18.10"
+"@graphql-tools/executor@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "@graphql-tools/executor@npm:1.3.2"
dependencies:
- "@babel/core": ^7.20.0
- "@babel/generator": ^7.20.5
- "@babel/parser": ^7.20.0
- "@babel/types": ^7.20.0
- "@expo/config": ~9.0.0-beta.0
- "@expo/env": ~0.3.0
- "@expo/json-file": ~8.3.0
- "@expo/spawn-async": ^1.7.2
- chalk: ^4.1.0
- debug: ^4.3.2
- find-yarn-workspace-root: ~2.0.0
- fs-extra: ^9.1.0
- getenv: ^1.0.0
- glob: ^7.2.3
- jsc-safe-url: ^0.2.4
- lightningcss: ~1.19.0
- postcss: ~8.4.32
- resolve-from: ^5.0.0
- checksum: d4292e925b58fd692477a122a6652e3f95eac8a7dca7319d7b14c03a6b3b7b6b7ebb26b263c31cdc085bc7f3460b7fa550538827915eab5ff0e60895e3527d73
+ "@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
-"@expo/osascript@npm:^2.0.31":
- version: 2.0.33
- resolution: "@expo/osascript@npm:2.0.33"
+"@graphql-tools/git-loader@npm:^8.0.0":
+ version: 8.0.8
+ resolution: "@graphql-tools/git-loader@npm:8.0.8"
dependencies:
- "@expo/spawn-async": ^1.5.0
- exec-async: ^2.2.0
- checksum: f1ae2e365ec82fcfefbdcd3ceb52da1b38c54e55a2ceb884ca06fb9259544c032b2f8133b803be152e86d79b8510fda8320811053894884819fa10b66268045d
+ "@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
-"@expo/package-manager@npm:^1.5.0":
- version: 1.5.2
- resolution: "@expo/package-manager@npm:1.5.2"
+"@graphql-tools/github-loader@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "@graphql-tools/github-loader@npm:8.0.3"
dependencies:
- "@expo/json-file": ^8.3.0
- "@expo/spawn-async": ^1.7.2
- ansi-regex: ^5.0.0
- chalk: ^4.0.0
- find-up: ^5.0.0
- find-yarn-workspace-root: ~2.0.0
- js-yaml: ^3.13.1
- micromatch: ^4.0.2
- npm-package-arg: ^7.0.0
- ora: ^3.4.0
- split: ^1.0.1
- sudo-prompt: 9.1.1
- checksum: 825e727106592bac98c82c69bf316b8b1ee20829f7f3e909cf374861b771cfa77d38b029f8b078341b2a9333004b4b90392f6f1a6a366c45ecf3f397798fb2a4
+ "@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
-"@expo/plist@npm:0.0.18":
- version: 0.0.18
- resolution: "@expo/plist@npm:0.0.18"
+"@graphql-tools/graphql-file-loader@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "@graphql-tools/graphql-file-loader@npm:8.0.2"
dependencies:
- "@xmldom/xmldom": ~0.7.0
- base64-js: ^1.2.3
- xmlbuilder: ^14.0.0
- checksum: 42f5743fcd2a07b55a9f048d27cf0f273510ab35dde1f7030b22dc8c30ab2cfb65c6e68f8aa58fbcfa00177fdc7c9696d0004083c9a47c36fd4ac7fea27d6ccc
+ "@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
-"@expo/plist@npm:^0.1.0":
- version: 0.1.3
- resolution: "@expo/plist@npm:0.1.3"
+"@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:
- "@xmldom/xmldom": ~0.7.7
- base64-js: ^1.2.3
- xmlbuilder: ^14.0.0
- checksum: 8abe78bed4d1849f2cddddd1a238c6fe5c2549a9dee40158224ff70112f31503db3f17a522b6e21f16eea66b5f4b46cc49d22f2b369067d00a88ef6d301a50cd
+ "@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.6":
- version: 7.0.6
- resolution: "@expo/prebuild-config@npm:7.0.6"
+"@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.0-beta.0
- "@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.84
- 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: 7210870c33b0fd78c4a1e758f801af3f47e16cf67a3a4a46a12bb10ad242e7925ec7f027dc348b6b4121c04ab76924630730f49debe086ccb95f72dc11c39c10
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: b6ee488e3720bc41710f7ccf7b499ae5cda63f80a2ebd35d6e2c80b6f36d1ff8345450c6c21f79c5aed8b001c87589c63d6a122236deb7d73ff17582038806c4
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/json-file-loader@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "@graphql-tools/json-file-loader@npm:8.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
+ globby: ^11.0.3
+ tslib: ^2.4.0
+ unixify: ^1.0.0
peerDependencies:
- expo-modules-autolinking: ">=0.8.1"
- checksum: b3715b10aa5aa9e60e97802feaaa6ddca4330752ec566d9f272e23417d00e2a298b6cc2f0d33f8a46a3c907f10b862d2975b737ba10e194ac834eae48847923b
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 56c53e22ac762ee2c668a33e1ab929cbea86b3ecb95a74290e085ac94385c22b2e7854b4d16094c8289cfaf76712c274bd99725d2f151ddad60d72edf1fdc412
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/load@npm:^8.0.0":
+ version: 8.0.3
+ resolution: "@graphql-tools/load@npm:8.0.3"
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/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/sdk-runtime-versions@npm:^1.0.0":
- version: 1.0.0
- resolution: "@expo/sdk-runtime-versions@npm:1.0.0"
- checksum: 0942d5a356f590e8dc795761456cc48b3e2d6a38ad2a02d6774efcdc5a70424e05623b4e3e5d2fec0cdc30f40dde05c14391c781607eed3971bf8676518bfd9d
+"@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:
+ "@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/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/optimize@npm:^1.3.0":
+ version: 1.4.0
+ resolution: "@graphql-tools/optimize@npm:1.4.0"
dependencies:
- cross-spawn: ^7.0.3
- checksum: d99e5ff6d303ec9b0105f97c4fa6c65bca526c7d4d0987997c35cc745fa8224adf009942d01808192ebb9fa30619a53316641958631e85cf17b773d9eeda2597
+ 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/vector-icons@npm:^14.0.0":
- version: 14.0.2
- resolution: "@expo/vector-icons@npm:14.0.2"
+"@graphql-tools/optimize@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "@graphql-tools/optimize@npm:2.0.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: 7f79c0e1852abc571308e887d27d613da5b797256c8c6eb6c5fe7ca77f09e61524778ae281cebc0b698c51d4fe1074e2b8e0d0627b8e2dcf505aa6ed09b49a2f
languageName: node
linkType: hard
-"@expo/xcpretty@npm:^4.3.0":
- version: 4.3.1
- resolution: "@expo/xcpretty@npm:4.3.1"
+"@graphql-tools/prisma-loader@npm:^8.0.0":
+ version: 8.0.16
+ resolution: "@graphql-tools/prisma-loader@npm:8.0.16"
dependencies:
- "@babel/code-frame": 7.10.4
+ "@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.0":
- version: 4.6.0
- resolution: "@gorhom/bottom-sheet@npm:4.6.0"
+"@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: a3f208066e514fcd68e8ee46658fc241a70da4c9b054848e4f3bc47761d453cf420251db684221d886ba67582d3b68d61890833b6c0017b75dccc8b3b8d0d4ee
+ 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:
@@ -2460,26 +3748,26 @@ __metadata:
languageName: node
linkType: hard
-"@helium/account-fetch-cache-hooks@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/account-fetch-cache-hooks@npm:0.9.7"
+"@helium/account-fetch-cache-hooks@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/account-fetch-cache-hooks@npm:0.9.14"
dependencies:
- "@helium/account-fetch-cache": ^0.9.7
+ "@helium/account-fetch-cache": ^0.9.14
"@solana/web3.js": ^1.78.8
react-async-hook: ^4.0.0
peerDependencies:
react: ^16.8 || ^17 || ^18
react-dom: ^16.8 || ^17 || ^18
- checksum: 0af43959dc0c963e2923a1d2998c645621571c9719a65b464174c3d54775169ff2183c90a724460b3e6ad0cd79db55ab1bb9d09afdb0ddf6ee00bc784779f5bd
+ checksum: a72612d800ffe5f8127050f8a5c033ac740cd22ba77d9e1091e3f2b77cfcbf02838da7e76042e6a4c0c2405d32ada1372a6bdbf275f8c55e589e58e36b0451af
languageName: node
linkType: hard
-"@helium/account-fetch-cache@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/account-fetch-cache@npm:0.9.7"
+"@helium/account-fetch-cache@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/account-fetch-cache@npm:0.9.14"
dependencies:
"@solana/web3.js": ^1.78.8
- checksum: 900d160b1cfa793c9b930011d8cd6c6c67bf15f7a1fcea82aba112cf21d87e836883712b44fca449aa6f17bed6fad9e92379996bca43ca392bd4ecef055c30a5
+ checksum: 519ed605322ed4ea519068d43666df640f899882e258453c11fe1cb83bcb82b8b5be02b38467ddf5b96cd531051dc9d62c22fccb8265c110e2a5653b3032b3d8
languageName: node
linkType: hard
@@ -2553,15 +3841,15 @@ __metadata:
languageName: node
linkType: hard
-"@helium/anchor-resolvers@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/anchor-resolvers@npm:0.9.7"
+"@helium/anchor-resolvers@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/anchor-resolvers@npm:0.9.14"
dependencies:
"@solana/spl-token": ^0.3.8
"@solana/web3.js": ^1.78.8
peerDependencies:
"@coral-xyz/anchor": ^0.28.0
- checksum: c15796832742b3eed06ae9c86b406a367432d981bb6b3d9e487b3632d013e733e115f22b5cc1701853b9435453e59a501dd2ad407b6f37a5059b2221c7efdb2a
+ checksum: 63377b47b92d5839468445d4f3277ade49b62b3ac80986542cf13aa021faef1a1c013f820521a7d3c618ff5a4dae5a91bf7fbcfa88fe30b4057de6169717d15f
languageName: node
linkType: hard
@@ -2591,16 +3879,16 @@ __metadata:
languageName: node
linkType: hard
-"@helium/circuit-breaker-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/circuit-breaker-sdk@npm:0.9.7"
+"@helium/circuit-breaker-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/circuit-breaker-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/idls": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: d9f3c56c1f81f06f8228dd078103fd766a8b818700ee8067c21bdc8f1701ba86d4a76fe1246859d0a7e676bf40e062887f03d99aab272bf20e9753e2b40cc821
+ checksum: 1ccbf2ca4de833066b63592756ce4cfc0b5135a97d8f3f3a006d948d226e094ab992a80643ee0ef5436540aa38e69a7bbc97070fef983be89e6ea21eff72b498
languageName: node
linkType: hard
@@ -2637,13 +3925,13 @@ __metadata:
languageName: node
linkType: hard
-"@helium/currency-utils@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/currency-utils@npm:0.9.7"
+"@helium/currency-utils@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/currency-utils@npm:0.9.14"
dependencies:
"@solana/spl-token": ^0.3.8
"@solana/web3.js": ^1.78.8
- checksum: 3f4a55fd1e74fedab58cf57b465aa85506ae0ad4616ec5c6c03361cbd30a58173ff965504675c1e647b86468fcd201f8b76b6b78409b855588b2b0569771e863
+ checksum: 77854dcc5149621ad9b97c54c1419e2f5f0bb7eee6cdacea2c2d56452087627fe4d1323b15eb84ab5f7cf1b58f1fdb051ce94e23edadd6b536f502b08a863480
languageName: node
linkType: hard
@@ -2688,36 +3976,36 @@ __metadata:
languageName: node
linkType: hard
-"@helium/data-credits-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/data-credits-sdk@npm:0.9.7"
+"@helium/data-credits-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/data-credits-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/circuit-breaker-sdk": ^0.9.7
- "@helium/helium-sub-daos-sdk": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/circuit-breaker-sdk": ^0.9.14
+ "@helium/helium-sub-daos-sdk": ^0.9.14
+ "@helium/idls": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
crypto-js: ^4.1.1
- checksum: 4de7b83c0c9960775a9d34374541af922e3a94c8f1a322bc81248bf8defcadcb78cdb1a2593fb7c99e4008e9bf052e189aaff8963e9173dbb3d48b5a501a1ec8
+ checksum: f6f7204a0de8cb40ee75f58407bb34e17d744af08ae649ecf232abfef104564ddc29f31d978f7b6fa2da644d56f4a9f114aa3dfd453019dfbacf81bb94481f37
languageName: node
linkType: hard
-"@helium/distributor-oracle@npm:0.9.7":
- version: 0.9.7
- resolution: "@helium/distributor-oracle@npm:0.9.7"
+"@helium/distributor-oracle@npm:0.9.14":
+ version: 0.9.14
+ resolution: "@helium/distributor-oracle@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
"@fastify/cors": ^8.1.1
- "@helium/account-fetch-cache": ^0.9.7
+ "@helium/account-fetch-cache": ^0.9.14
"@helium/address": ^4.10.2
- "@helium/helium-entity-manager-sdk": ^0.9.7
- "@helium/helium-sub-daos-sdk": ^0.9.7
- "@helium/idls": ^0.9.7
- "@helium/lazy-distributor-sdk": ^0.9.7
- "@helium/rewards-oracle-sdk": ^0.9.7
- "@helium/spl-utils": ^0.9.7
+ "@helium/helium-entity-manager-sdk": ^0.9.14
+ "@helium/helium-sub-daos-sdk": ^0.9.14
+ "@helium/idls": ^0.9.14
+ "@helium/lazy-distributor-sdk": ^0.9.14
+ "@helium/rewards-oracle-sdk": ^0.9.14
+ "@helium/spl-utils": ^0.9.14
"@metaplex-foundation/mpl-bubblegum": ^0.7.0
"@solana/spl-token": ^0.3.8
"@types/sequelize": ^4.28.14
@@ -2733,20 +4021,20 @@ __metadata:
prom-client: ^15.0.0
sequelize: ^6.28.0
typescript-collections: ^1.3.3
- checksum: d3a6e9a9afe4cb96df21c664577a16b25d4f5e6ee4e68561089034c81d99ac7fadae2509087db335f81334a86e7faa8cda7a32717d21092084ac7c88fc17a88c
+ checksum: 4cb6a95b24d02f02e5b0620646c1265ef464a551775c302d686f1f620eb1b3baef99eadd4707e6692fa8458784648a57cb27a717699bdf4650bf394ecfa92ab9
languageName: node
linkType: hard
-"@helium/fanout-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/fanout-sdk@npm:0.9.7"
+"@helium/fanout-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/fanout-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/idls": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 31104d246c9fafcc4b4ff446ed1b6403f59a121538fc9fee5bc553f5d6b8290b689f9943c1ae9afbfda46e7e01a86caa09ce8c587ca91a5684e1a5c3e17741bc
+ checksum: 9f84f1e5b141d5cacde952b805ee2a8f18ace52c89bda8dc09a8aba6d675afa5458f7f7d7acf21b69720b159790e6306fe7cf62af992ae6c04a72e64bdf524b5
languageName: node
linkType: hard
@@ -2788,32 +4076,32 @@ __metadata:
languageName: node
linkType: hard
-"@helium/helium-entity-manager-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/helium-entity-manager-sdk@npm:0.9.7"
+"@helium/helium-entity-manager-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/helium-entity-manager-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
"@helium/address": ^4.10.2
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/helium-sub-daos-sdk": ^0.9.7
- "@helium/idls": ^0.9.7
- "@helium/no-emit-sdk": ^0.9.7
- "@helium/spl-utils": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/helium-sub-daos-sdk": ^0.9.14
+ "@helium/idls": ^0.9.14
+ "@helium/no-emit-sdk": ^0.9.14
+ "@helium/spl-utils": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
crypto-js: ^4.1.1
js-sha256: ^0.9.0
- checksum: 08d8bf2f811f4509015579673ae890894c9c5c3417815c592043d81c3775294600735c7f01bbd78d2150353ca4e64b89e58f4668ca4b2ed278d32d6afc17f110
+ checksum: 24c6825b2226ba40ad433d1c7ec132effef96f535b5fb34d2abbf94c7dfed218b21cc53fc2ecb151c7152703e3b2c8359e383446fc15d89f6022f1918f6ab9de
languageName: node
linkType: hard
-"@helium/helium-react-hooks@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/helium-react-hooks@npm:0.9.7"
+"@helium/helium-react-hooks@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/helium-react-hooks@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/account-fetch-cache": ^0.9.7
- "@helium/account-fetch-cache-hooks": ^0.9.7
+ "@helium/account-fetch-cache": ^0.9.14
+ "@helium/account-fetch-cache-hooks": ^0.9.14
"@solana/spl-token": ^0.3.8
"@solana/web3.js": ^1.78.8
bs58: ^4.0.1
@@ -2823,7 +4111,7 @@ __metadata:
"@solana/wallet-adapter-react": ^0.15.32
react: ^16.8 || ^17 || ^18
react-dom: ^16.8 || ^17 || ^18
- checksum: 0614fe24e03f02c7ec1edc3ecad3de2020ec9bfe004a4a0a6921aad5f8046c1ca3426fe3089e92667e35e14e21e4d70fca599bb2e42ce18ecd3c88f914279bdb
+ checksum: cd5106ab16e0003758220609852274415cee1ed10210d291ba66cdefaa904ec73c61a5158b1bb2d859fc73310f7a6de41a348f4c6e1246bae7df56702ea783c3
languageName: node
linkType: hard
@@ -2857,18 +4145,18 @@ __metadata:
languageName: node
linkType: hard
-"@helium/helium-sub-daos-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/helium-sub-daos-sdk@npm:0.9.7"
+"@helium/helium-sub-daos-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/helium-sub-daos-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/circuit-breaker-sdk": ^0.9.7
- "@helium/treasury-management-sdk": ^0.9.7
- "@helium/voter-stake-registry-sdk": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/circuit-breaker-sdk": ^0.9.14
+ "@helium/treasury-management-sdk": ^0.9.14
+ "@helium/voter-stake-registry-sdk": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 09f188a86c492d90c9e1f45d56c4edd976819832b12b63e9b1d378274da2f39580bd54a860edcd6ac2f596d1f0046a232236880eddc2d8b8ebdeae8135a46938
+ checksum: 91eef5ad462687c7eeda5cd4692d0450c99f4b8ad6cf1158956c0d8d788883996f82673b93cb3011688ee611d957062a87c965cb73900304587e1a95d20d0f6b
languageName: node
linkType: hard
@@ -2917,16 +4205,16 @@ __metadata:
languageName: node
linkType: hard
-"@helium/idls@npm:0.9.7, @helium/idls@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/idls@npm:0.9.7"
+"@helium/idls@npm:0.9.14, @helium/idls@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/idls@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
"@solana/web3.js": ^1.78.8
bn.js: ^5.2.0
borsh: ^0.7.0
bs58: ^4.0.1
- checksum: 5c2586b6b9f8063ed7cd9b135c29de430e24b7e84d643dc7031dd06aab4f9dbb8b5b9d861be6e433e500f3d055fc8eccee08d99ff52a28c2c66c5302d5bc0cac
+ checksum: a3ea8d58c1885d2ec392b6a256c0cd7e89e3b89824810dcbd0c8979f832c8683449895aed1654af08ff3d6ebddc52e34181c89a5a113e62a7b64f377a7574819
languageName: node
linkType: hard
@@ -2969,16 +4257,16 @@ __metadata:
languageName: node
linkType: hard
-"@helium/lazy-distributor-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/lazy-distributor-sdk@npm:0.9.7"
+"@helium/lazy-distributor-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/lazy-distributor-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/circuit-breaker-sdk": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/circuit-breaker-sdk": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: cc4980ef07b5a458a0952147b624f505d304f16a147eb7b336a8dfbf4359a775ac4a228f3e3ba01af750bd0e39b83256eb4402a7e9d8429cba17c93e32641869
+ checksum: af6a6ba42e0450c821fe5b971be4c98c27c4ea2b02d8cefcf80bad00b17e42db4b2cd2127d396c5b8bb238be1c5436bdf2f3ee63a9057976ee6ce76293a130a4
languageName: node
linkType: hard
@@ -3055,16 +4343,16 @@ __metadata:
languageName: node
linkType: hard
-"@helium/no-emit-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/no-emit-sdk@npm:0.9.7"
+"@helium/no-emit-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/no-emit-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
"@helium/anchor-resolvers": ^0.5.0
"@helium/idls": ^0.5.0
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: d6409dfd6991c172758fc84bbf1b252d0c44ce7cc27a53b08ea1e81b6280577c841fa4442df5e60df938e20f77e9c7f9db957b04bbdee3774ada1bd469de4625
+ checksum: 56de168dd265582b1e2f680bb790fd77c7f0470704414b5cd2ae3d708da553d5457e4449f96abe57fe723928ecba393cb8acbd8c9ae60a79794f8c61bec9ba1c
languageName: node
linkType: hard
@@ -3111,6 +4399,21 @@ __metadata:
languageName: node
linkType: hard
+"@helium/position-voting-rewards-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/position-voting-rewards-sdk@npm:0.9.14"
+ dependencies:
+ "@coral-xyz/anchor": ^0.28.0
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/idls": ^0.9.14
+ "@helium/spl-utils": ^0.9.14
+ "@solana/spl-token": ^0.3.8
+ bn.js: ^5.2.0
+ bs58: ^4.0.1
+ checksum: a0790b0165ae67a68b678b2ef850dbbe9e450f5105584ff7d091d1bac40afcf03731fbfdceae039c0f9e01fff506dd6b92d5d3f39ab6390f35b6ab8a37bd5c0a
+ languageName: node
+ linkType: hard
+
"@helium/proposal-sdk@npm:^0.0.13":
version: 0.0.13
resolution: "@helium/proposal-sdk@npm:0.0.13"
@@ -3215,27 +4518,27 @@ __metadata:
languageName: node
linkType: hard
-"@helium/rewards-oracle-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/rewards-oracle-sdk@npm:0.9.7"
+"@helium/rewards-oracle-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/rewards-oracle-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/idls": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 007441b2af11c54c5c3b7a3c634d32f3499fc37b91b9079da12c884d09dae6eb958dbb1dfd881ed16b535ad8dd6f27e18b26d50f9ca4f11fea5fbed521a0c12c
+ checksum: c18999a873a3fe3a00d984736de25dddd2fa9ddab8966898c9bcb3dab7dc70b00e4fb0342ad89bc669e501ec84924c2d827c6559d24f39e2e4cfe5a0976d3e02
languageName: node
linkType: hard
-"@helium/spl-utils@npm:0.9.7, @helium/spl-utils@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/spl-utils@npm:0.9.7"
+"@helium/spl-utils@npm:0.9.14, @helium/spl-utils@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/spl-utils@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/account-fetch-cache": ^0.9.7
+ "@helium/account-fetch-cache": ^0.9.14
"@helium/address": ^4.10.2
- "@helium/anchor-resolvers": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
"@metaplex-foundation/mpl-token-metadata": ^2.10.0
"@solana/spl-account-compression": ^0.1.7
"@solana/spl-token": ^0.3.8
@@ -3244,7 +4547,7 @@ __metadata:
bn.js: ^5.2.0
borsh: ^0.7.0
bs58: ^4.0.1
- checksum: c7ed4c8a4701b019ac1dca008e1da7095f9f7bdbd685792c83b11480137a5c55473c672b9eb26ae3431d11e87c9e0d6a93870ed9d223b8ecc56008443b58c230
+ checksum: f604647b63e0432eec4384427d1cd823485d4236a980e2a7f347f286aea3fd21cc3700fd7f58e853e166e17d879967b8776964528f169fb1442529ef839c0521
languageName: node
linkType: hard
@@ -3299,9 +4602,9 @@ __metadata:
languageName: node
linkType: hard
-"@helium/sus@npm:0.9.7":
- version: 0.9.7
- resolution: "@helium/sus@npm:0.9.7"
+"@helium/sus@npm:0.9.14":
+ version: 0.9.14
+ resolution: "@helium/sus@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
"@metaplex-foundation/mpl-token-metadata": ^2.10.0
@@ -3310,7 +4613,7 @@ __metadata:
axios: ^1.6.5
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 20888988d0b2e65b1cc66a28092b1b7792a9ccdce3e9d86b9e90b5dc32add29e701ef6e323f1bfdad1008a6b8fc8daffa43e20e58facdfe2e0974842a3bf68b1
+ checksum: ff4be446ea060511924f32ddaac4236bd3db0a0ae59065f4565dec4505e2b31f709ae53322cdb240a85dd9a6daa0c2600f826eeda3a4b306de259660d578581a
languageName: node
linkType: hard
@@ -3368,34 +4671,35 @@ __metadata:
languageName: node
linkType: hard
-"@helium/treasury-management-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/treasury-management-sdk@npm:0.9.7"
+"@helium/treasury-management-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/treasury-management-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/circuit-breaker-sdk": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/circuit-breaker-sdk": ^0.9.14
+ "@helium/idls": ^0.9.14
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 0297fb5afd6646a8e2d544d7eadaf55bfed67cdb5531e3bac5c0d4fc02874921174023bebda5445e8a2f39bef93d86ce0f41ab1b3191f54fe98574f0548c3a28
+ checksum: a46291b78876591fac3900ac3784e6fe7427fae56982a2b7830c2a5194c919307ef520e98a1f66b84cec1896c59905f3a917497fa0557f67ff7ae07dff3dfa0f
languageName: node
linkType: hard
-"@helium/voter-stake-registry-hooks@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/voter-stake-registry-hooks@npm:0.9.7"
+"@helium/voter-stake-registry-hooks@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/voter-stake-registry-hooks@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/account-fetch-cache": ^0.9.7
- "@helium/account-fetch-cache-hooks": ^0.9.7
- "@helium/circuit-breaker-sdk": ^0.9.7
- "@helium/helium-react-hooks": ^0.9.7
- "@helium/helium-sub-daos-sdk": ^0.9.7
+ "@helium/account-fetch-cache": ^0.9.14
+ "@helium/account-fetch-cache-hooks": ^0.9.14
+ "@helium/circuit-breaker-sdk": ^0.9.14
+ "@helium/helium-react-hooks": ^0.9.14
+ "@helium/helium-sub-daos-sdk": ^0.9.14
"@helium/modular-governance-hooks": ^0.0.12
"@helium/modular-governance-idls": ^0.0.12
- "@helium/spl-utils": ^0.9.7
- "@helium/voter-stake-registry-sdk": ^0.9.7
+ "@helium/position-voting-rewards-sdk": ^0.9.14
+ "@helium/spl-utils": ^0.9.14
+ "@helium/voter-stake-registry-sdk": ^0.9.14
"@solana/wallet-adapter-base": ^0.9.22
"@solana/wallet-adapter-react": ^0.15.32
"@solana/web3.js": ^1.78.8
@@ -3406,24 +4710,24 @@ __metadata:
peerDependencies:
react: ^16.8 || ^17 || ^18
react-dom: ^16.8 || ^17 || ^18
- checksum: b6b577ef118228cf9290c692b1b1c0973ee4aceb70240988e8a85ff8eaf3edb0927f1126c2a7d6c76be4adb713ae83d268abbcf793c870fd9bd74986e434a05d
+ checksum: 1e8d393afc5db230afc1e42802a136a0bb1c06f5e2b48e6b048ea91122a70df0f0b25c6cd83228b4cf91791a0bd0abcaa926223308a67acc84d6fc8171ac001b
languageName: node
linkType: hard
-"@helium/voter-stake-registry-sdk@npm:^0.9.7":
- version: 0.9.7
- resolution: "@helium/voter-stake-registry-sdk@npm:0.9.7"
+"@helium/voter-stake-registry-sdk@npm:^0.9.14":
+ version: 0.9.14
+ resolution: "@helium/voter-stake-registry-sdk@npm:0.9.14"
dependencies:
"@coral-xyz/anchor": ^0.28.0
- "@helium/anchor-resolvers": ^0.9.7
- "@helium/idls": ^0.9.7
+ "@helium/anchor-resolvers": ^0.9.14
+ "@helium/idls": ^0.9.14
"@helium/nft-proxy-sdk": ^0.0.12
- "@helium/spl-utils": ^0.9.7
+ "@helium/spl-utils": ^0.9.14
"@metaplex-foundation/mpl-token-metadata": ^2.10.0
"@solana/spl-token": ^0.3.8
bn.js: ^5.2.0
bs58: ^4.0.1
- checksum: 51121199819f0a30aa7d5f9ebcac3e0f104721d38fcae10df47c5ecf207e3f015ad136fcbf67353e3b9f890b680c3b2a6def0995eab7918f3fce62d1fc3924b5
+ checksum: 855b2dc578adc80e03b799c7fa0a5ca4b7202b63adcd3d96a7a738833a0a102dde2b01825882dbce9c405380066f1a99db58d43e48269307c9b1015eedae8db6
languageName: node
linkType: hard
@@ -3811,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"
@@ -4102,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"
@@ -4158,6 +5425,18 @@ __metadata:
languageName: node
linkType: hard
+"@metaplex-foundation/beet-solana@npm:^0.3.0, @metaplex-foundation/beet-solana@npm:^0.3.1":
+ version: 0.3.1
+ resolution: "@metaplex-foundation/beet-solana@npm:0.3.1"
+ dependencies:
+ "@metaplex-foundation/beet": ">=0.1.0"
+ "@solana/web3.js": ^1.56.2
+ bs58: ^5.0.0
+ debug: ^4.3.4
+ checksum: 5405ec57c8cdb2dce016bf96f1cbd96ae185d6c764b8bdd1aaa68028e1970ad4815e7eb026a61703f57c33ddac261e47874e013bb03d84fa74ad78fce4b6e7cd
+ languageName: node
+ linkType: hard
+
"@metaplex-foundation/beet@npm:0.7.1, @metaplex-foundation/beet@npm:>=0.1.0, @metaplex-foundation/beet@npm:^0.7.1":
version: 0.7.1
resolution: "@metaplex-foundation/beet@npm:0.7.1"
@@ -4169,6 +5448,28 @@ __metadata:
languageName: node
linkType: hard
+"@metaplex-foundation/beet@npm:^0.4.0":
+ version: 0.4.0
+ resolution: "@metaplex-foundation/beet@npm:0.4.0"
+ dependencies:
+ ansicolors: ^0.3.2
+ bn.js: ^5.2.0
+ debug: ^4.3.3
+ checksum: f0cd43da9a707d88852d8b51413ab46b18b1f9fe36a80a75ec1408a2b04544785c428aee76c94d288717e8a6ed3dfc0f3989f1eb206e4e441574cc0a573149d3
+ languageName: node
+ linkType: hard
+
+"@metaplex-foundation/beet@npm:^0.6.1":
+ version: 0.6.1
+ resolution: "@metaplex-foundation/beet@npm:0.6.1"
+ dependencies:
+ ansicolors: ^0.3.2
+ bn.js: ^5.2.0
+ debug: ^4.3.3
+ checksum: 8ee340feb08dce44657f1ebe55c17d6c617ae8b44ea086a8d43aadeded7ee919b3d541b0c3e74a8cd3dbc16e749f6228333ca2ea50e2b52194f14e5d59587aaa
+ languageName: node
+ linkType: hard
+
"@metaplex-foundation/cusper@npm:^0.0.2":
version: 0.0.2
resolution: "@metaplex-foundation/cusper@npm:0.0.2"
@@ -4176,6 +5477,52 @@ __metadata:
languageName: node
linkType: hard
+"@metaplex-foundation/js@npm:^0.19.5":
+ version: 0.19.5
+ resolution: "@metaplex-foundation/js@npm:0.19.5"
+ dependencies:
+ "@bundlr-network/client": ^0.8.8
+ "@metaplex-foundation/beet": 0.7.1
+ "@metaplex-foundation/mpl-auction-house": ^2.3.0
+ "@metaplex-foundation/mpl-bubblegum": ^0.6.2
+ "@metaplex-foundation/mpl-candy-guard": ^0.3.0
+ "@metaplex-foundation/mpl-candy-machine": ^5.0.0
+ "@metaplex-foundation/mpl-candy-machine-core": ^0.1.2
+ "@metaplex-foundation/mpl-token-metadata": ^2.11.0
+ "@noble/ed25519": ^1.7.1
+ "@noble/hashes": ^1.1.3
+ "@solana/spl-account-compression": ^0.1.8
+ "@solana/spl-token": ^0.3.5
+ "@solana/web3.js": ^1.63.1
+ bignumber.js: ^9.0.2
+ bn.js: ^5.2.1
+ bs58: ^5.0.0
+ buffer: ^6.0.3
+ debug: ^4.3.4
+ eventemitter3: ^4.0.7
+ lodash.clonedeep: ^4.5.0
+ lodash.isequal: ^4.5.0
+ merkletreejs: ^0.2.32
+ mime: ^3.0.0
+ node-fetch: ^2.6.7
+ checksum: 6b8dfcca3b30c6c4bd2666ed95aa5b30b919251eeca34fcc7afdf975e28a251b9116da66a88351e0495235a0d1fef3b4841702735a7aebb9dadef8dac3c1fa51
+ languageName: node
+ linkType: hard
+
+"@metaplex-foundation/mpl-auction-house@npm:^2.3.0":
+ version: 2.5.1
+ resolution: "@metaplex-foundation/mpl-auction-house@npm:2.5.1"
+ dependencies:
+ "@metaplex-foundation/beet": ^0.6.1
+ "@metaplex-foundation/beet-solana": ^0.3.1
+ "@metaplex-foundation/cusper": ^0.0.2
+ "@solana/spl-token": ^0.3.5
+ "@solana/web3.js": ^1.56.2
+ bn.js: ^5.2.0
+ checksum: d6e671742ed587a0a6cb3060cb1b529f43379b3ee476466f39da6a75f0764fe5037d6ae743753438c2c203a6ae0b4bc1ce2ac21041beab08107c789e698587b1
+ languageName: node
+ linkType: hard
+
"@metaplex-foundation/mpl-bubblegum@npm:0.6.0":
version: 0.6.0
resolution: "@metaplex-foundation/mpl-bubblegum@npm:0.6.0"
@@ -4193,6 +5540,23 @@ __metadata:
languageName: node
linkType: hard
+"@metaplex-foundation/mpl-bubblegum@npm:^0.6.2":
+ version: 0.6.2
+ resolution: "@metaplex-foundation/mpl-bubblegum@npm:0.6.2"
+ dependencies:
+ "@metaplex-foundation/beet": 0.7.1
+ "@metaplex-foundation/beet-solana": 0.4.0
+ "@metaplex-foundation/cusper": ^0.0.2
+ "@metaplex-foundation/mpl-token-metadata": ^2.5.2
+ "@solana/spl-account-compression": ^0.1.4
+ "@solana/spl-token": ^0.1.8
+ "@solana/web3.js": ^1.50.1
+ bn.js: ^5.2.0
+ js-sha3: ^0.8.0
+ checksum: 2c58b4d23035fb9d5d3ecbc3c273969ea1aebdb1dd195785df1e2ea022297a4405a7485d603f334b8617e2b362abfe5ff061dfe1b829dfa849c7200725240892
+ languageName: node
+ linkType: hard
+
"@metaplex-foundation/mpl-bubblegum@npm:^0.7.0":
version: 0.7.0
resolution: "@metaplex-foundation/mpl-bubblegum@npm:0.7.0"
@@ -4209,6 +5573,45 @@ __metadata:
languageName: node
linkType: hard
+"@metaplex-foundation/mpl-candy-guard@npm:^0.3.0":
+ version: 0.3.2
+ resolution: "@metaplex-foundation/mpl-candy-guard@npm:0.3.2"
+ dependencies:
+ "@metaplex-foundation/beet": ^0.4.0
+ "@metaplex-foundation/beet-solana": ^0.3.0
+ "@metaplex-foundation/cusper": ^0.0.2
+ "@solana/web3.js": ^1.66.2
+ bn.js: ^5.2.0
+ checksum: cc8521bd1d96cb32c8a79ae71d4fac01ae3f22a76ee95ae40169d1d6cf0d92679a3262abb06c9ff5f15d7254e00830e09937d60d5679d2233b4c51eafc1e5172
+ languageName: node
+ linkType: hard
+
+"@metaplex-foundation/mpl-candy-machine-core@npm:^0.1.2":
+ version: 0.1.2
+ resolution: "@metaplex-foundation/mpl-candy-machine-core@npm:0.1.2"
+ dependencies:
+ "@metaplex-foundation/beet": ^0.4.0
+ "@metaplex-foundation/beet-solana": ^0.3.0
+ "@metaplex-foundation/cusper": ^0.0.2
+ "@solana/web3.js": ^1.56.2
+ bn.js: ^5.2.0
+ checksum: c407c402142568a098f99adb88001a28ce55b8963d858c6491cf70d526cfb761960457b5b1226d957d9dd3fccf899a1334cc88962ef64a9d32fd6ce15cc1b2f1
+ languageName: node
+ linkType: hard
+
+"@metaplex-foundation/mpl-candy-machine@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "@metaplex-foundation/mpl-candy-machine@npm:5.1.0"
+ dependencies:
+ "@metaplex-foundation/beet": ^0.7.1
+ "@metaplex-foundation/beet-solana": ^0.4.0
+ "@metaplex-foundation/cusper": ^0.0.2
+ "@solana/spl-token": ^0.3.6
+ "@solana/web3.js": ^1.66.2
+ checksum: 5f219a84b2a21056f81e956a2a48079d97ceafdd0dd8a24dc77f28fc28662b84401614558a31e1f755a936909f314e31482270606282c1c0970424f20f22ba1d
+ languageName: node
+ linkType: hard
+
"@metaplex-foundation/mpl-token-metadata@npm:2.10.0":
version: 2.10.0
resolution: "@metaplex-foundation/mpl-token-metadata@npm:2.10.0"
@@ -4224,7 +5627,7 @@ __metadata:
languageName: node
linkType: hard
-"@metaplex-foundation/mpl-token-metadata@npm:^2.10.0, @metaplex-foundation/mpl-token-metadata@npm:^2.5.2":
+"@metaplex-foundation/mpl-token-metadata@npm:^2.10.0, @metaplex-foundation/mpl-token-metadata@npm:^2.11.0, @metaplex-foundation/mpl-token-metadata@npm:^2.5.2":
version: 2.13.0
resolution: "@metaplex-foundation/mpl-token-metadata@npm:2.13.0"
dependencies:
@@ -4281,6 +5684,22 @@ __metadata:
languageName: node
linkType: hard
+"@noble/curves@npm:^1.4.2":
+ version: 1.6.0
+ resolution: "@noble/curves@npm:1.6.0"
+ dependencies:
+ "@noble/hashes": 1.5.0
+ checksum: 258f3feb2a6098cf35521562ecb7d452fd728e8a008ff9f1ef435184f9d0c782ceb8f7b7fa8df3317c3be7a19f53995ee124cd05c8080b130bd42e3cb072f24d
+ languageName: node
+ linkType: hard
+
+"@noble/ed25519@npm:^1.6.1, @noble/ed25519@npm:^1.7.1":
+ version: 1.7.3
+ resolution: "@noble/ed25519@npm:1.7.3"
+ checksum: 45169927d51de513e47bbeebff3a603433c4ac7579e1b8c5034c380a0afedbe85e6959be3d69584a7a5ed6828d638f8f28879003b9bb2fb5f22d8aa2d88fd5fe
+ languageName: node
+ linkType: hard
+
"@noble/hashes@npm:1.3.2":
version: 1.3.2
resolution: "@noble/hashes@npm:1.3.2"
@@ -4295,6 +5714,13 @@ __metadata:
languageName: node
linkType: hard
+"@noble/hashes@npm:1.5.0, @noble/hashes@npm:^1.1.3, @noble/hashes@npm:^1.4.0":
+ version: 1.5.0
+ resolution: "@noble/hashes@npm:1.5.0"
+ checksum: 9cc031d5c888c455bfeef76af649b87f75380a4511405baea633c1e4912fd84aff7b61e99716f0231d244c9cfeda1fafd7d718963e6a0c674ed705e9b1b4f76b
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -4322,6 +5748,13 @@ __metadata:
languageName: node
linkType: hard
+"@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
+
"@npmcli/agent@npm:^2.0.0":
version: 2.2.2
resolution: "@npmcli/agent@npm:2.2.2"
@@ -4459,6 +5892,22 @@ __metadata:
languageName: node
linkType: hard
+"@randlabs/communication-bridge@npm:1.0.1":
+ version: 1.0.1
+ resolution: "@randlabs/communication-bridge@npm:1.0.1"
+ checksum: 9573e7f848c23c2b600e87b2b6a819894ad69ee0019da72b6ee3da086e52deb5a5055cb001d8f2fc014528b24c5dc476479ddb3ecf70e94abec07c80d0c771ed
+ languageName: node
+ linkType: hard
+
+"@randlabs/myalgo-connect@npm:^1.1.2":
+ version: 1.4.2
+ resolution: "@randlabs/myalgo-connect@npm:1.4.2"
+ dependencies:
+ "@randlabs/communication-bridge": 1.0.1
+ checksum: 2328adc8f4badae43fce9a29c0de00bc7dd56baee326eb7ed0f8eac69bfdd6e11ef3bb41cb452bad5e340f5edc8a5e5b7233b163f93aaeb80c20a57164a94fe3
+ languageName: node
+ linkType: hard
+
"@react-native-async-storage/async-storage@npm:1.18.1":
version: 1.18.1
resolution: "@react-native-async-storage/async-storage@npm:1.18.1"
@@ -4722,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"
@@ -5034,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
@@ -5062,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"
@@ -5244,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"
@@ -5296,13 +6783,13 @@ __metadata:
languageName: node
linkType: hard
-"@shopify/restyle@npm:1.8.0":
- version: 1.8.0
- resolution: "@shopify/restyle@npm:1.8.0"
+"@shopify/restyle@npm:2.4.2":
+ version: 2.4.2
+ resolution: "@shopify/restyle@npm:2.4.2"
peerDependencies:
- react: ">=16.8.0"
- react-native: ">=0.59.0"
- checksum: bc3ae3b90ae56dc5f22035635c30588ad1422c90694feaabda0f8d8cb7e066f28a621584badad4fa633ee6910380dcacb2ce636c108722117ec9102d768beec9
+ react: "*"
+ react-native: "*"
+ checksum: a8025d82f1742bdd639ea1422bd0759a86b342b8488d46edad8a70630d941ababdf36de29dac0cd2d33062b18da8222154091c2088b03fa79645a29bb6ee3f69
languageName: node
linkType: hard
@@ -5420,6 +6907,17 @@ __metadata:
languageName: node
linkType: hard
+"@solana/codecs-core@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/codecs-core@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/errors": 2.0.0-rc.1
+ peerDependencies:
+ typescript: ">=5"
+ checksum: e3a138cbdc2b87c6296c449384b684ca2f90cf212cee1cf0a1f30385c3acc72c9a3dc2e60e3152723b9fa5640635bcf69ce06581d83113986ede05d41139f0ba
+ languageName: node
+ linkType: hard
+
"@solana/codecs-data-structures@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/codecs-data-structures@npm:2.0.0-preview.2"
@@ -5431,6 +6929,19 @@ __metadata:
languageName: node
linkType: hard
+"@solana/codecs-data-structures@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/codecs-data-structures@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/codecs-core": 2.0.0-rc.1
+ "@solana/codecs-numbers": 2.0.0-rc.1
+ "@solana/errors": 2.0.0-rc.1
+ peerDependencies:
+ typescript: ">=5"
+ checksum: 7c24700be7c935fc066dc70e1a02c32d9f17393d3898074e6dcff2c2083012dc8c5583fff5ee04f8ce4578c57bb708688f5e52aad301aa5543aab293640a0b21
+ languageName: node
+ linkType: hard
+
"@solana/codecs-numbers@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/codecs-numbers@npm:2.0.0-preview.2"
@@ -5441,6 +6952,18 @@ __metadata:
languageName: node
linkType: hard
+"@solana/codecs-numbers@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/codecs-numbers@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/codecs-core": 2.0.0-rc.1
+ "@solana/errors": 2.0.0-rc.1
+ peerDependencies:
+ typescript: ">=5"
+ checksum: 370c1f94970e969b1f523d47714ddd751b68f622967455e2376590af0f230e027dce365bd54a9017fbc064ed21447f795c775c46285222c42a11b8ed46a41570
+ languageName: node
+ linkType: hard
+
"@solana/codecs-strings@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/codecs-strings@npm:2.0.0-preview.2"
@@ -5454,6 +6977,20 @@ __metadata:
languageName: node
linkType: hard
+"@solana/codecs-strings@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/codecs-strings@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/codecs-core": 2.0.0-rc.1
+ "@solana/codecs-numbers": 2.0.0-rc.1
+ "@solana/errors": 2.0.0-rc.1
+ peerDependencies:
+ fastestsmallesttextencoderdecoder: ^1.0.22
+ typescript: ">=5"
+ checksum: 0706605311508b02f7dc4bfde6f93237337ecde051c83f172a121b52676e2a21af90f916624f57c0e80bbe420412ed98c1e7ae90a583761b028cc6a883fa4a0e
+ languageName: node
+ linkType: hard
+
"@solana/codecs@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/codecs@npm:2.0.0-preview.2"
@@ -5467,6 +7004,21 @@ __metadata:
languageName: node
linkType: hard
+"@solana/codecs@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/codecs@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/codecs-core": 2.0.0-rc.1
+ "@solana/codecs-data-structures": 2.0.0-rc.1
+ "@solana/codecs-numbers": 2.0.0-rc.1
+ "@solana/codecs-strings": 2.0.0-rc.1
+ "@solana/options": 2.0.0-rc.1
+ peerDependencies:
+ typescript: ">=5"
+ checksum: 8586abfd1e2792008a447c29efc22e0bfefd7d97a8025090dd49ec07c8c860e51c44355ab74faf43e23336f3dd2e1353238fa4b009d3fe60ff3f02b46a96aa04
+ languageName: node
+ linkType: hard
+
"@solana/errors@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/errors@npm:2.0.0-preview.2"
@@ -5479,6 +7031,20 @@ __metadata:
languageName: node
linkType: hard
+"@solana/errors@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/errors@npm:2.0.0-rc.1"
+ dependencies:
+ chalk: ^5.3.0
+ commander: ^12.1.0
+ peerDependencies:
+ typescript: ">=5"
+ bin:
+ errors: bin/cli.mjs
+ checksum: 906892a892d250c2236449b875b174e0e19ade788146d0e63da23c83d89b98a762770c276341fae8f73959efc57d01090e0e979d111b12ac0e451f2402a8d092
+ languageName: node
+ linkType: hard
+
"@solana/options@npm:2.0.0-preview.2":
version: 2.0.0-preview.2
resolution: "@solana/options@npm:2.0.0-preview.2"
@@ -5489,6 +7055,21 @@ __metadata:
languageName: node
linkType: hard
+"@solana/options@npm:2.0.0-rc.1":
+ version: 2.0.0-rc.1
+ resolution: "@solana/options@npm:2.0.0-rc.1"
+ dependencies:
+ "@solana/codecs-core": 2.0.0-rc.1
+ "@solana/codecs-data-structures": 2.0.0-rc.1
+ "@solana/codecs-numbers": 2.0.0-rc.1
+ "@solana/codecs-strings": 2.0.0-rc.1
+ "@solana/errors": 2.0.0-rc.1
+ peerDependencies:
+ typescript: ">=5"
+ checksum: 63f3ed04e56ca232023fcf35ddab8f01a1ba7aae932990908657dec833ff4133ad0af279417d4bce291367903dbd3b962287796a22dd0aaa1d3e3290613a442e
+ languageName: node
+ linkType: hard
+
"@solana/spl-account-compression@npm:0.1.4":
version: 0.1.4
resolution: "@solana/spl-account-compression@npm:0.1.4"
@@ -5503,7 +7084,7 @@ __metadata:
languageName: node
linkType: hard
-"@solana/spl-account-compression@npm:^0.1.4, @solana/spl-account-compression@npm:^0.1.7":
+"@solana/spl-account-compression@npm:^0.1.4, @solana/spl-account-compression@npm:^0.1.7, @solana/spl-account-compression@npm:^0.1.8":
version: 0.1.10
resolution: "@solana/spl-account-compression@npm:0.1.10"
dependencies:
@@ -5530,6 +7111,18 @@ __metadata:
languageName: node
linkType: hard
+"@solana/spl-token-metadata@npm:^0.1.2":
+ version: 0.1.5
+ resolution: "@solana/spl-token-metadata@npm:0.1.5"
+ dependencies:
+ "@solana/codecs": 2.0.0-rc.1
+ "@solana/spl-type-length-value": 0.1.0
+ peerDependencies:
+ "@solana/web3.js": ^1.95.3
+ checksum: dffe1bf05c5c60cb3a725044c2013c5d3dfeed2e0ae99dd083916cf92cc433f5d87b631f38fc8ae0aac5ed8c1d266be1c8dc7c868da5253be076fe7ce49a31b8
+ languageName: node
+ linkType: hard
+
"@solana/spl-token-metadata@npm:^0.1.4":
version: 0.1.4
resolution: "@solana/spl-token-metadata@npm:0.1.4"
@@ -5582,6 +7175,20 @@ __metadata:
languageName: node
linkType: hard
+"@solana/spl-token@npm:^0.3.5":
+ version: 0.3.11
+ resolution: "@solana/spl-token@npm:0.3.11"
+ dependencies:
+ "@solana/buffer-layout": ^4.0.0
+ "@solana/buffer-layout-utils": ^0.2.0
+ "@solana/spl-token-metadata": ^0.1.2
+ buffer: ^6.0.3
+ peerDependencies:
+ "@solana/web3.js": ^1.88.0
+ checksum: 84faef5e8ed798e21870728817f650d572a0d0b8c8ac6591f75325d7e89831df396f48384083a65f8b79c30ea4cbfabd0ccb4fbc7a4f20953d133b746ed8b99d
+ languageName: node
+ linkType: hard
+
"@solana/spl-token@npm:^0.3.6, @solana/spl-token@npm:^0.3.8":
version: 0.3.8
resolution: "@solana/spl-token@npm:0.3.8"
@@ -5604,7 +7211,7 @@ __metadata:
languageName: node
linkType: hard
-"@solana/wallet-adapter-base@npm:^0.9.17, @solana/wallet-adapter-base@npm:^0.9.22, @solana/wallet-adapter-base@npm:^0.9.23":
+"@solana/wallet-adapter-base@npm:^0.9.17, @solana/wallet-adapter-base@npm:^0.9.2, @solana/wallet-adapter-base@npm:^0.9.22, @solana/wallet-adapter-base@npm:^0.9.23":
version: 0.9.23
resolution: "@solana/wallet-adapter-base@npm:0.9.23"
dependencies:
@@ -5705,13 +7312,36 @@ __metadata:
languageName: node
linkType: hard
-"@solana/web3.js@npm:^1.21.0, @solana/web3.js@npm:^1.32.0, @solana/web3.js@npm:^1.43.4, @solana/web3.js@npm:^1.50.1, @solana/web3.js@npm:^1.56.2, @solana/web3.js@npm:^1.66.2, @solana/web3.js@npm:^1.68.0, @solana/web3.js@npm:^1.69.0, @solana/web3.js@npm:^1.78.4, @solana/web3.js@npm:^1.78.8, @solana/web3.js@npm:^1.87.6":
- version: 1.91.4
- resolution: "@solana/web3.js@npm:1.91.4"
+"@solana/web3.js@npm:^1.21.0, @solana/web3.js@npm:^1.32.0, @solana/web3.js@npm:^1.43.4, @solana/web3.js@npm:^1.50.1, @solana/web3.js@npm:^1.56.2, @solana/web3.js@npm:^1.66.2, @solana/web3.js@npm:^1.68.0, @solana/web3.js@npm:^1.69.0, @solana/web3.js@npm:^1.78.4, @solana/web3.js@npm:^1.78.8, @solana/web3.js@npm:^1.87.6":
+ version: 1.91.4
+ resolution: "@solana/web3.js@npm:1.91.4"
+ dependencies:
+ "@babel/runtime": ^7.23.4
+ "@noble/curves": ^1.2.0
+ "@noble/hashes": ^1.3.3
+ "@solana/buffer-layout": ^4.0.1
+ agentkeepalive: ^4.5.0
+ bigint-buffer: ^1.1.5
+ bn.js: ^5.2.1
+ borsh: ^0.7.0
+ bs58: ^4.0.1
+ buffer: 6.0.3
+ fast-stable-stringify: ^1.0.0
+ jayson: ^4.1.0
+ node-fetch: ^2.7.0
+ rpc-websockets: ^7.5.1
+ superstruct: ^0.14.2
+ checksum: 9f6ac2f64ac05043cb367c09d5b4f4b859060618dbffc7a27da35fccdac0be9bd84b83899c9547efedc061fa7e20af283a9bacff01972bd047089809facfbdfe
+ languageName: node
+ linkType: hard
+
+"@solana/web3.js@npm:^1.36.0, @solana/web3.js@npm:^1.63.1":
+ version: 1.95.3
+ resolution: "@solana/web3.js@npm:1.95.3"
dependencies:
- "@babel/runtime": ^7.23.4
- "@noble/curves": ^1.2.0
- "@noble/hashes": ^1.3.3
+ "@babel/runtime": ^7.25.0
+ "@noble/curves": ^1.4.2
+ "@noble/hashes": ^1.4.0
"@solana/buffer-layout": ^4.0.1
agentkeepalive: ^4.5.0
bigint-buffer: ^1.1.5
@@ -5720,11 +7350,11 @@ __metadata:
bs58: ^4.0.1
buffer: 6.0.3
fast-stable-stringify: ^1.0.0
- jayson: ^4.1.0
+ jayson: ^4.1.1
node-fetch: ^2.7.0
- rpc-websockets: ^7.5.1
- superstruct: ^0.14.2
- checksum: 9f6ac2f64ac05043cb367c09d5b4f4b859060618dbffc7a27da35fccdac0be9bd84b83899c9547efedc061fa7e20af283a9bacff01972bd047089809facfbdfe
+ rpc-websockets: ^9.0.2
+ superstruct: ^2.0.2
+ checksum: 6951eb12275de09ef9422fc65982b7496f3d11253b4cd1b09694dd2135d92aa272a04a7adf50ef0136a459b08ea40e07f6e7cbf1970cae44d6193d93fe6acc1f
languageName: node
linkType: hard
@@ -5898,6 +7528,13 @@ __metadata:
languageName: node
linkType: hard
+"@supercharge/promise-pool@npm:^2.1.0":
+ version: 2.4.0
+ resolution: "@supercharge/promise-pool@npm:2.4.0"
+ checksum: d21223256ba05c34a29742172e2b625627038e731f511de0b728c638531096ce12d1a4156fd04e3b34eec980ce8445a66a9d8d070fde7886c9b33a0d759ab2e9
+ languageName: node
+ linkType: hard
+
"@svgr/babel-plugin-add-jsx-attribute@npm:^4.2.0":
version: 4.2.0
resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:4.2.0"
@@ -6013,6 +7650,15 @@ __metadata:
languageName: node
linkType: hard
+"@swc/helpers@npm:^0.5.11":
+ version: 0.5.13
+ resolution: "@swc/helpers@npm:0.5.13"
+ dependencies:
+ tslib: ^2.4.0
+ checksum: d50c2c10da6ef940af423c6b03ad9c3c94cf9de59314b1e921a7d1bcc081a6074481c9d67b655fc8fe66a73288f98b25950743792a63882bfb5793b362494fc0
+ languageName: node
+ linkType: hard
+
"@tanstack/query-core@npm:5.45.0":
version: 5.45.0
resolution: "@tanstack/query-core@npm:5.45.0"
@@ -6349,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"
@@ -6445,6 +8098,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:11.11.6":
+ version: 11.11.6
+ resolution: "@types/node@npm:11.11.6"
+ checksum: 075f1c011cf568e49701419acbcb55c24906b3bb5a34d9412a3b88f228a7a78401a5ad4d3e1cd6855c99aaea5ef96e37fc86ca097e50f06da92cf822befc1fff
+ languageName: node
+ linkType: hard
+
"@types/node@npm:^12.12.54":
version: 12.20.55
resolution: "@types/node@npm:12.20.55"
@@ -6452,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:
@@ -6620,6 +8280,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/uuid@npm:^8.3.4":
+ version: 8.3.4
+ resolution: "@types/uuid@npm:8.3.4"
+ checksum: 6f11f3ff70f30210edaa8071422d405e9c1d4e53abbe50fdce365150d3c698fe7bbff65c1e71ae080cbfb8fded860dbb5e174da96fdbbdfcaa3fb3daa474d20f
+ languageName: node
+ linkType: hard
+
"@types/validator@npm:*, @types/validator@npm:^13.7.17":
version: 13.11.1
resolution: "@types/validator@npm:13.11.1"
@@ -6636,6 +8303,24 @@ __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"
+ dependencies:
+ "@types/node": "*"
+ checksum: ddefb6ad1671f70ce73b38a5f47f471d4d493864fca7c51f002a86e5993d031294201c5dced6d5018fb8905ad46888d65c7f20dd54fc165910b69f42fba9a6d0
+ languageName: node
+ linkType: hard
+
"@types/yargs-parser@npm:*":
version: 21.0.0
resolution: "@types/yargs-parser@npm:21.0.0"
@@ -7349,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"
@@ -7356,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
@@ -7458,6 +9187,13 @@ __metadata:
languageName: node
linkType: hard
+"aes-js@npm:3.0.0":
+ version: 3.0.0
+ resolution: "aes-js@npm:3.0.0"
+ checksum: 251e26d533cd1a915b44896b17d5ed68c24a02484cfdd2e74ec700a309267db96651ea4eb657bf20aac32a3baa61f6e34edf8e2fec2de440a655da9942d334b8
+ languageName: node
+ linkType: hard
+
"agent-base@npm:6":
version: 6.0.2
resolution: "agent-base@npm:6.0.2"
@@ -7533,6 +9269,31 @@ __metadata:
languageName: node
linkType: hard
+"algo-msgpack-with-bigint@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "algo-msgpack-with-bigint@npm:2.1.1"
+ checksum: 81645fc1248f42b048713f2218a7e108711da34cd229b7a58d18af8c041ea1f72051437afb4fcca2d78e6960094b8a88a2e6a45b6d48bca176b5cad24703a976
+ languageName: node
+ linkType: hard
+
+"algosdk@npm:^1.13.1":
+ version: 1.24.1
+ resolution: "algosdk@npm:1.24.1"
+ dependencies:
+ algo-msgpack-with-bigint: ^2.1.1
+ buffer: ^6.0.2
+ cross-fetch: ^3.1.5
+ hi-base32: ^0.5.1
+ js-sha256: ^0.9.0
+ js-sha3: ^0.8.0
+ js-sha512: ^0.8.0
+ json-bigint: ^1.0.0
+ tweetnacl: ^1.0.3
+ vlq: ^2.0.4
+ checksum: 3b6960dddec3d7d37a1505dcb3c6997740c5b02fa076a140efcf51eaddd83b7a7c8f56bab3001ec0ac7b1ccdd264e5a41d051b8bf5b9b72762e338c704547203
+ languageName: node
+ linkType: hard
+
"angry-purple-tiger@npm:1.0.5":
version: 1.0.5
resolution: "angry-purple-tiger@npm:1.0.5"
@@ -7556,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:
@@ -7667,6 +9428,30 @@ __metadata:
languageName: node
linkType: hard
+"arbundles@npm:^0.6.21":
+ version: 0.6.23
+ resolution: "arbundles@npm:0.6.23"
+ dependencies:
+ "@noble/ed25519": ^1.6.1
+ "@randlabs/myalgo-connect": ^1.1.2
+ "@solana/wallet-adapter-base": ^0.9.2
+ algosdk: ^1.13.1
+ arweave: ^1.11.4
+ arweave-stream-tx: ^1.1.0
+ avsc: "https://github.com/Irys-xyz/avsc#csp-fixes"
+ axios: ^0.21.3
+ base64url: ^3.0.1
+ bs58: ^4.0.1
+ ethers: ^5.5.1
+ keccak: ^3.0.2
+ multistream: ^4.1.0
+ process: ^0.11.10
+ secp256k1: ^4.0.2
+ tmp-promise: ^3.0.2
+ checksum: 7968b998df35b12e84297310c7941665bb4be55ecc059b1f797ebe6cc90da129e20d87fda7aaa007cfe0416173a33d014aff3abf8710ec065a2f4f19f04e9a36
+ languageName: node
+ linkType: hard
+
"archy@npm:^1.0.0":
version: 1.0.0
resolution: "archy@npm:1.0.0"
@@ -7674,6 +9459,15 @@ __metadata:
languageName: node
linkType: hard
+"arconnect@npm:^0.4.2":
+ version: 0.4.2
+ resolution: "arconnect@npm:0.4.2"
+ dependencies:
+ arweave: ^1.10.13
+ checksum: 5b2f262a93a3a25d4bd6f72eb3afe4b13d0e94ed12f88b7bcf3501d25839e74c2882fa1a1a9b527ac9c6da22ca2f407c07fc49e3d898a4f24b5d66a1901173f8
+ languageName: node
+ linkType: hard
+
"arg@npm:5.0.2":
version: 5.0.2
resolution: "arg@npm:5.0.2"
@@ -7846,6 +9640,29 @@ __metadata:
languageName: node
linkType: hard
+"arweave-stream-tx@npm:^1.1.0":
+ version: 1.2.2
+ resolution: "arweave-stream-tx@npm:1.2.2"
+ dependencies:
+ exponential-backoff: ^3.1.0
+ peerDependencies:
+ arweave: ^1.10.0
+ checksum: 7db2ef3078f28d25e9be096b7680da08b6d9a3b8f44216770a2c08be90ae192569ab948fc9904b930b61f8e0fef8a4e7f77165c2e18b68f3d586274034540c5c
+ languageName: node
+ linkType: hard
+
+"arweave@npm:^1.10.13, arweave@npm:^1.11.4":
+ version: 1.15.5
+ resolution: "arweave@npm:1.15.5"
+ dependencies:
+ arconnect: ^0.4.2
+ asn1.js: ^5.4.1
+ base64-js: ^1.5.1
+ bignumber.js: ^9.0.2
+ checksum: c1fb2144fd7255ff043c213658646b147b3103a5839598abd2d215bcc618346e4361feba0cf19a3d4efe1e5ce7ab3c385954940c253115a99f08b2c1b002ba18
+ languageName: node
+ linkType: hard
+
"asap@npm:~2.0.3, asap@npm:~2.0.6":
version: 2.0.6
resolution: "asap@npm:2.0.6"
@@ -7853,7 +9670,7 @@ __metadata:
languageName: node
linkType: hard
-"asn1.js@npm:^5.2.0":
+"asn1.js@npm:^5.2.0, asn1.js@npm:^5.4.1":
version: 5.4.1
resolution: "asn1.js@npm:5.4.1"
dependencies:
@@ -7941,6 +9758,15 @@ __metadata:
languageName: node
linkType: hard
+"async-retry@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "async-retry@npm:1.3.3"
+ dependencies:
+ retry: 0.13.1
+ checksum: 38a7152ff7265a9321ea214b9c69e8224ab1febbdec98efbbde6e562f17ff68405569b796b1c5271f354aef8783665d29953f051f68c1fc45306e61aec82fdc4
+ languageName: node
+ linkType: hard
+
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
@@ -7971,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"
@@ -7980,6 +9813,13 @@ __metadata:
languageName: node
linkType: hard
+"avsc@https://github.com/Irys-xyz/avsc#csp-fixes":
+ version: 5.4.7
+ resolution: "avsc@https://github.com/Irys-xyz/avsc.git#commit=a730cc8018b79e114b6a3381bbb57760a24c6cef"
+ checksum: 94d2b1b20c51fecb11a2e596d042c057055c11d9275e8718b090b81a90e82134571553f2c250001770f5a92cfed4e8687fdd77b138c120eaa424db8335d4a1a9
+ languageName: node
+ linkType: hard
+
"avvio@npm:^8.2.1":
version: 8.2.1
resolution: "avvio@npm:8.2.1"
@@ -8049,7 +9889,7 @@ __metadata:
languageName: node
linkType: hard
-"axios@npm:^0.21.1":
+"axios@npm:^0.21.1, axios@npm:^0.21.3":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
@@ -8058,6 +9898,15 @@ __metadata:
languageName: node
linkType: hard
+"axios@npm:^0.25.0":
+ version: 0.25.0
+ resolution: "axios@npm:0.25.0"
+ dependencies:
+ follow-redirects: ^1.14.7
+ checksum: 2a8a3787c05f2a0c9c3878f49782357e2a9f38945b93018fb0c4fd788171c43dceefbb577988628e09fea53952744d1ecebde234b561f1e703aa43e0a598a3ad
+ languageName: node
+ linkType: hard
+
"axios@npm:^1.3.0, axios@npm:^1.3.6, axios@npm:^1.5.0, axios@npm:^1.6.5":
version: 1.6.7
resolution: "axios@npm:1.6.7"
@@ -8391,6 +10240,13 @@ __metadata:
languageName: node
linkType: hard
+"base64url@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "base64url@npm:3.0.1"
+ checksum: a77b2a3a526b3343e25be424de3ae0aa937d78f6af7c813ef9020ef98001c0f4e2323afcd7d8b2d2978996bf8c42445c3e9f60c218c622593e5fdfd54a3d6e18
+ languageName: node
+ linkType: hard
+
"base@npm:^0.11.1":
version: 0.11.2
resolution: "base@npm:0.11.2"
@@ -8423,6 +10279,13 @@ __metadata:
languageName: node
linkType: hard
+"bech32@npm:1.1.4":
+ version: 1.1.4
+ resolution: "bech32@npm:1.1.4"
+ checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b
+ languageName: node
+ linkType: hard
+
"better-opn@npm:~3.0.2":
version: 3.0.2
resolution: "better-opn@npm:3.0.2"
@@ -8463,7 +10326,7 @@ __metadata:
languageName: node
linkType: hard
-"bignumber.js@npm:^9.0.0, bignumber.js@npm:^9.0.1, bignumber.js@npm:^9.1.1":
+"bignumber.js@npm:^9.0.0, bignumber.js@npm:^9.0.1, bignumber.js@npm:^9.0.2, bignumber.js@npm:^9.1.1":
version: 9.1.2
resolution: "bignumber.js@npm:9.1.2"
checksum: 582c03af77ec9cb0ebd682a373ee6c66475db94a4325f92299621d544aa4bd45cb45fd60001610e94aef8ae98a0905fa538241d9638d4422d57abbeeac6fadaf
@@ -8493,6 +10356,28 @@ __metadata:
languageName: node
linkType: hard
+"bip39-light@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "bip39-light@npm:1.0.7"
+ dependencies:
+ create-hash: ^1.1.0
+ pbkdf2: ^3.0.9
+ checksum: 10ffceacc34e4d2c6449e2f45bba90a3e3455e63e51044da289f68e66cbc1727a9f489a76f199dd5ac50b6be50a7f075e546ed62ab236a50e215480a27567661
+ languageName: node
+ linkType: hard
+
+"bip39@npm:3.0.2":
+ version: 3.0.2
+ resolution: "bip39@npm:3.0.2"
+ dependencies:
+ "@types/node": 11.11.6
+ create-hash: ^1.1.0
+ pbkdf2: ^3.0.9
+ randombytes: ^2.0.1
+ checksum: 71798582b4d1cc7f20d11372413c4514f124d302e6b38e7f9126d4759fca3e9fbccb431429a6ab16130dd67193de3d781122fcd4bca0a653be654d4aa13490c5
+ languageName: node
+ linkType: hard
+
"bip39@npm:^3.1.0":
version: 3.1.0
resolution: "bip39@npm:3.1.0"
@@ -8522,6 +10407,20 @@ __metadata:
languageName: node
linkType: hard
+"bn.js@npm:4.11.6":
+ version: 4.11.6
+ resolution: "bn.js@npm:4.11.6"
+ checksum: db23047bf06fdf9cf74401c8e76bca9f55313c81df382247d2c753868b368562e69171716b81b7038ada8860af18346fd4bcd1cf9d4963f923fe8e54e61cb58a
+ languageName: node
+ linkType: hard
+
+"bn.js@npm:5.2.0":
+ version: 5.2.0
+ resolution: "bn.js@npm:5.2.0"
+ checksum: 6117170393200f68b35a061ecbf55d01dd989302e7b3c798a3012354fa638d124f0b2f79e63f77be5556be80322a09c40339eda6413ba7468524c0b6d4b4cb7a
+ languageName: node
+ linkType: hard
+
"bn.js@npm:5.2.1, bn.js@npm:^5.0.0, bn.js@npm:^5.1.0, bn.js@npm:^5.1.1, bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1":
version: 5.2.1
resolution: "bn.js@npm:5.2.1"
@@ -8543,6 +10442,17 @@ __metadata:
languageName: node
linkType: hard
+"borsh@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "borsh@npm:0.6.0"
+ dependencies:
+ bn.js: ^5.2.0
+ bs58: ^4.0.0
+ text-encoding-utf-8: ^1.0.2
+ checksum: 633986769e931dd9d156c0d52a315cd3bb0546c24df84e28fa04859cccbebd9107f1621bd594d4a63ba23c7cda2931a8d97e54952ee766a097d3c2434f80b009
+ languageName: node
+ linkType: hard
+
"borsh@npm:^0.7.0":
version: 0.7.0
resolution: "borsh@npm:0.7.0"
@@ -8636,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"
@@ -8730,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"
@@ -8816,6 +10749,13 @@ __metadata:
languageName: node
linkType: hard
+"buffer-reverse@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "buffer-reverse@npm:1.0.1"
+ checksum: e350872a89b17af0a7e1bd7a73239a535164f3f010b0800add44f2e52bd0511548dc5b96c20309effba969868c385023d2d02a0add6155f6a76da7b3073b77bd
+ languageName: node
+ linkType: hard
+
"buffer-writer@npm:2.0.0":
version: 2.0.0
resolution: "buffer-writer@npm:2.0.0"
@@ -8841,7 +10781,7 @@ __metadata:
languageName: node
linkType: hard
-"buffer@npm:6.0.3, buffer@npm:^6.0.1, buffer@npm:^6.0.3, buffer@npm:~6.0.3":
+"buffer@npm:6.0.3, buffer@npm:^6.0.1, buffer@npm:^6.0.2, buffer@npm:^6.0.3, buffer@npm:~6.0.3":
version: 6.0.3
resolution: "buffer@npm:6.0.3"
dependencies:
@@ -8878,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"
@@ -8967,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"
@@ -9018,6 +10977,31 @@ __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"
+ checksum: 59ce65958dc0f2e76e7007fe8d5a0a85801b950bb957779c11948776f0e7a1290b9638bfd2da92b4b8bebd7584f92a8c38d4e6613659c9637783a6993026b08b
+ 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"
@@ -9043,7 +11027,7 @@ __metadata:
languageName: node
linkType: hard
-"chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2":
+"chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
dependencies:
@@ -9060,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"
@@ -9067,6 +11107,13 @@ __metadata:
languageName: node
linkType: hard
+"chardet@npm:^0.7.0":
+ version: 0.7.0
+ resolution: "chardet@npm:0.7.0"
+ checksum: 6fd5da1f5d18ff5712c1e0aed41da200d7c51c28f11b36ee3c7b483f3696dabc08927fc6b227735eb8f0e1215c9a8abd8154637f3eff8cada5959df7f58b024d
+ languageName: node
+ linkType: hard
+
"charenc@npm:0.0.2, charenc@npm:~0.0.1":
version: 0.0.2
resolution: "charenc@npm:0.0.2"
@@ -9170,6 +11217,23 @@ __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"
+ checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6
+ languageName: node
+ linkType: hard
+
"cliui@npm:^6.0.0":
version: 6.0.0
resolution: "cliui@npm:6.0.0"
@@ -9341,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"
@@ -9364,7 +11435,7 @@ __metadata:
languageName: node
linkType: hard
-"commander@npm:^12.0.0":
+"commander@npm:^12.0.0, commander@npm:^12.1.0":
version: 12.1.0
resolution: "commander@npm:12.1.0"
checksum: 68e9818b00fc1ed9cdab9eb16905551c2b768a317ae69a5e3c43924c2b20ac9bb65b27e1cab36aeda7b6496376d4da908996ba2c0b5d79463e0fb1e77935d514
@@ -9392,6 +11463,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^8.2.0":
+ version: 8.3.0
+ resolution: "commander@npm:8.3.0"
+ checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0
+ languageName: node
+ linkType: hard
+
"commander@npm:^9.4.1":
version: 9.5.0
resolution: "commander@npm:9.5.0"
@@ -9399,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"
@@ -9496,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"
@@ -9583,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"
@@ -9655,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"
@@ -9693,6 +11815,13 @@ __metadata:
languageName: node
linkType: hard
+"crypto-js@npm:^3.1.9-1":
+ version: 3.3.0
+ resolution: "crypto-js@npm:3.3.0"
+ checksum: 193923143a4784b2f974366068d96fe8280168fd3fef2bfea9551a5c3e32096f5a8fa49ff4eeb5bd0b9716d325618d38cfbe6125e359a4ef488fbca93e600824
+ languageName: node
+ linkType: hard
+
"crypto-js@npm:^4.1.1":
version: 4.1.1
resolution: "crypto-js@npm:4.1.1"
@@ -9821,6 +11950,39 @@ __metadata:
languageName: node
linkType: hard
+"csv-generate@npm:^4.4.1":
+ version: 4.4.1
+ resolution: "csv-generate@npm:4.4.1"
+ checksum: 9a0ddd963836f7a6c011a57ba188753ed5cf57083f3d9a2c811392b5a3b6be21e265f653365cbb66641567cda5f37bdb3618117de8db51fbc6f574c7a693e334
+ languageName: node
+ linkType: hard
+
+"csv-parse@npm:^5.5.6":
+ version: 5.5.6
+ resolution: "csv-parse@npm:5.5.6"
+ checksum: ee06f97f674487dc1d001b360de8ea510a41b9d971abf43bcf9c3be22c83a3634df0d3ebfbe52fd49d145077066be7ff9f25de3fc6b71aefb973099b04147a25
+ languageName: node
+ linkType: hard
+
+"csv-stringify@npm:^6.5.1":
+ version: 6.5.1
+ resolution: "csv-stringify@npm:6.5.1"
+ checksum: 5eb8167ee944f5328c53c733d8c4b1eea88fb9e510abec430e2fcb4be6c4ce008b92e90da7825d424fe74d22c85405add7f89b9dcf82ffe2bf0a1cf31536057a
+ languageName: node
+ linkType: hard
+
+"csv@npm:^6.0.5":
+ version: 6.3.10
+ resolution: "csv@npm:6.3.10"
+ dependencies:
+ csv-generate: ^4.4.1
+ csv-parse: ^5.5.6
+ csv-stringify: ^6.5.1
+ stream-transform: ^3.3.2
+ checksum: 409ccdd31025e8b758e66c7fff35c2d0c38fd2f07f687150b8c2a930d1fbec2964fb6295a07c04c4d564978906c34d744e6cbd6c7ac828029d8d9d6d17eacfe3
+ languageName: node
+ linkType: hard
+
"dag-map@npm:~1.0.0":
version: 1.0.2
resolution: "dag-map@npm:1.0.2"
@@ -9868,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"
@@ -10118,13 +12287,27 @@ __metadata:
languageName: node
linkType: hard
-"depd@npm:2.0.0":
+"depd@npm:2.0.0, depd@npm:^2.0.0":
version: 2.0.0
resolution: "depd@npm:2.0.0"
checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a
languageName: node
linkType: hard
+"depd@npm:~1.1.2":
+ version: 1.1.2
+ resolution: "depd@npm:1.1.2"
+ checksum: 6b406620d269619852885ce15965272b829df6f409724415e0002c8632ab6a8c0a08ec1f0bd2add05dc7bd7507606f7e2cc034fa24224ab829580040b835ecd9
+ 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"
@@ -10136,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"
@@ -10171,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"
@@ -10344,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
@@ -10367,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"
@@ -10410,7 +12596,14 @@ __metadata:
languageName: node
linkType: hard
-"elliptic@npm:^6.5.3":
+"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"
dependencies:
@@ -10475,13 +12668,6 @@ __metadata:
languageName: node
linkType: hard
-"encode-utf8@npm:^1.0.3":
- version: 1.0.3
- resolution: "encode-utf8@npm:1.0.3"
- checksum: 550224bf2a104b1d355458c8a82e9b4ea07f9fc78387bc3a49c151b940ad26473de8dc9e121eefc4e84561cb0b46de1e4cd2bc766f72ee145e9ea9541482817f
- languageName: node
- linkType: hard
-
"encodeurl@npm:~1.0.2":
version: 1.0.2
resolution: "encodeurl@npm:1.0.2"
@@ -10602,6 +12788,17 @@ __metadata:
languageName: node
linkType: hard
+"error-polyfill@npm:^0.1.3":
+ version: 0.1.3
+ resolution: "error-polyfill@npm:0.1.3"
+ dependencies:
+ capability: ^0.2.5
+ o3: ^1.0.3
+ u3: ^0.1.1
+ checksum: 1aee485841310e1f4d10cde0a5c8ac840311c94914bb1aed8fd71826be84dd5dba3d4ab937f39c0b970edb3d0a76cfb5d001ec979db6c68858b5f75c1f504c52
+ languageName: node
+ linkType: hard
+
"error-stack-parser@npm:^2.0.6":
version: 2.1.4
resolution: "error-stack-parser@npm:2.1.4"
@@ -10783,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"
@@ -11274,7 +13478,16 @@ __metadata:
languageName: node
linkType: hard
-"ethereum-cryptography@npm:^2.2.1":
+"ethereum-bloom-filters@npm:^1.0.6":
+ version: 1.2.0
+ resolution: "ethereum-bloom-filters@npm:1.2.0"
+ dependencies:
+ "@noble/hashes": ^1.4.0
+ checksum: 3a4d11495a5845483b78eca6455a915835d691df09a8c5754785c6bdfb5d18382d7e65b066a1c092493c1d87850c6a77243136996a231baec82f22c727e15258
+ languageName: node
+ linkType: hard
+
+"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.2.1":
version: 2.2.1
resolution: "ethereum-cryptography@npm:2.2.1"
dependencies:
@@ -11286,6 +13499,54 @@ __metadata:
languageName: node
linkType: hard
+"ethers@npm:^5.5.1":
+ version: 5.7.2
+ resolution: "ethers@npm:5.7.2"
+ dependencies:
+ "@ethersproject/abi": 5.7.0
+ "@ethersproject/abstract-provider": 5.7.0
+ "@ethersproject/abstract-signer": 5.7.0
+ "@ethersproject/address": 5.7.0
+ "@ethersproject/base64": 5.7.0
+ "@ethersproject/basex": 5.7.0
+ "@ethersproject/bignumber": 5.7.0
+ "@ethersproject/bytes": 5.7.0
+ "@ethersproject/constants": 5.7.0
+ "@ethersproject/contracts": 5.7.0
+ "@ethersproject/hash": 5.7.0
+ "@ethersproject/hdnode": 5.7.0
+ "@ethersproject/json-wallets": 5.7.0
+ "@ethersproject/keccak256": 5.7.0
+ "@ethersproject/logger": 5.7.0
+ "@ethersproject/networks": 5.7.1
+ "@ethersproject/pbkdf2": 5.7.0
+ "@ethersproject/properties": 5.7.0
+ "@ethersproject/providers": 5.7.2
+ "@ethersproject/random": 5.7.0
+ "@ethersproject/rlp": 5.7.0
+ "@ethersproject/sha2": 5.7.0
+ "@ethersproject/signing-key": 5.7.0
+ "@ethersproject/solidity": 5.7.0
+ "@ethersproject/strings": 5.7.0
+ "@ethersproject/transactions": 5.7.0
+ "@ethersproject/units": 5.7.0
+ "@ethersproject/wallet": 5.7.0
+ "@ethersproject/web": 5.7.1
+ "@ethersproject/wordlists": 5.7.0
+ checksum: b7c08cf3e257185a7946117dbbf764433b7ba0e77c27298dec6088b3bc871aff711462b0621930c56880ff0a7ceb8b1d3a361ffa259f93377b48e34107f62553
+ languageName: node
+ linkType: hard
+
+"ethjs-unit@npm:0.1.6":
+ version: 0.1.6
+ resolution: "ethjs-unit@npm:0.1.6"
+ dependencies:
+ bn.js: 4.11.6
+ number-to-bn: 1.7.0
+ checksum: df6b4752ff7461a59a20219f4b1684c631ea601241c39660e3f6c6bd63c950189723841c22b3c6c0ebeb3c9fc99e0e803e3c613101206132603705fcbcf4def5
+ languageName: node
+ linkType: hard
+
"event-target-shim@npm:^5.0.0, event-target-shim@npm:^5.0.1":
version: 5.0.1
resolution: "event-target-shim@npm:5.0.1"
@@ -11300,6 +13561,13 @@ __metadata:
languageName: node
linkType: hard
+"eventemitter3@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "eventemitter3@npm:5.0.1"
+ checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8
+ languageName: node
+ linkType: hard
+
"events@npm:1.1.1, events@npm:^1.0.2":
version: 1.1.1
resolution: "events@npm:1.1.1"
@@ -11514,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"
@@ -11583,7 +13860,7 @@ __metadata:
languageName: node
linkType: hard
-"exponential-backoff@npm:^3.1.1":
+"exponential-backoff@npm:^3.1.0, exponential-backoff@npm:^3.1.1":
version: 3.1.1
resolution: "exponential-backoff@npm:3.1.1"
checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48
@@ -11609,6 +13886,17 @@ __metadata:
languageName: node
linkType: hard
+"external-editor@npm:^3.0.3":
+ version: 3.1.0
+ resolution: "external-editor@npm:3.1.0"
+ dependencies:
+ chardet: ^0.7.0
+ iconv-lite: ^0.4.24
+ tmp: ^0.0.33
+ checksum: 1c2a616a73f1b3435ce04030261bed0e22d4737e14b090bb48e58865da92529c9f2b05b893de650738d55e692d071819b45e1669259b2b354bc3154d27a698c7
+ languageName: node
+ linkType: hard
+
"extglob@npm:^2.0.4":
version: 2.0.4
resolution: "extglob@npm:2.0.4"
@@ -11625,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"
@@ -11708,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:
@@ -11858,6 +14153,15 @@ __metadata:
languageName: node
linkType: hard
+"figures@npm:^3.0.0":
+ version: 3.2.0
+ resolution: "figures@npm:3.2.0"
+ dependencies:
+ escape-string-regexp: ^1.0.5
+ checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b
+ languageName: node
+ linkType: hard
+
"file-entry-cache@npm:^6.0.1":
version: 6.0.1
resolution: "file-entry-cache@npm:6.0.1"
@@ -11895,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"
@@ -12043,6 +14356,16 @@ __metadata:
languageName: node
linkType: hard
+"follow-redirects@npm:^1.14.7":
+ version: 1.15.9
+ resolution: "follow-redirects@npm:1.15.9"
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ checksum: 859e2bacc7a54506f2bf9aacb10d165df78c8c1b0ceb8023f966621b233717dab56e8d08baadc3ad3b9db58af290413d585c999694b7c146aaf2616340c3d2a6
+ languageName: node
+ linkType: hard
+
"fontfaceobserver@npm:^2.1.0":
version: 2.3.0
resolution: "fontfaceobserver@npm:2.3.0"
@@ -12310,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"
@@ -12527,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:
@@ -12538,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"
@@ -12695,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:."
@@ -12705,36 +15091,40 @@ __metadata:
"@babel/runtime": 7.20.13
"@bonfida/spl-name-service": ^1.1.1
"@coral-xyz/anchor": ^0.28.0
- "@gorhom/bottom-sheet": 4.6.0
+ "@gorhom/bottom-sheet": 5.0.4
"@gorhom/portal": 1.0.14
- "@helium/account-fetch-cache": 0.9.7
- "@helium/account-fetch-cache-hooks": 0.9.7
+ "@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.14
+ "@helium/account-fetch-cache-hooks": 0.9.14
"@helium/address": 4.10.2
- "@helium/circuit-breaker-sdk": ^0.9.7
+ "@helium/circuit-breaker-sdk": ^0.9.14
"@helium/crypto-react-native": 4.8.0
- "@helium/currency-utils": ^0.9.7
- "@helium/data-credits-sdk": ^0.9.7
- "@helium/distributor-oracle": 0.9.7
- "@helium/fanout-sdk": ^0.9.7
- "@helium/helium-entity-manager-sdk": ^0.9.7
- "@helium/helium-react-hooks": 0.9.7
- "@helium/helium-sub-daos-sdk": ^0.9.7
+ "@helium/currency-utils": ^0.9.14
+ "@helium/data-credits-sdk": ^0.9.14
+ "@helium/distributor-oracle": 0.9.14
+ "@helium/fanout-sdk": ^0.9.14
+ "@helium/helium-entity-manager-sdk": ^0.9.14
+ "@helium/helium-react-hooks": 0.9.14
+ "@helium/helium-sub-daos-sdk": ^0.9.14
"@helium/http": 4.7.5
- "@helium/idls": 0.9.7
- "@helium/lazy-distributor-sdk": ^0.9.7
+ "@helium/idls": 0.9.14
+ "@helium/lazy-distributor-sdk": ^0.9.14
"@helium/modular-governance-hooks": ^0.0.13
"@helium/modular-governance-idls": 0.0.13
"@helium/onboarding": 4.11.0
"@helium/organization-sdk": ^0.0.13
"@helium/proto-ble": 4.0.0
"@helium/react-native-sdk": 3.0.5
- "@helium/spl-utils": 0.9.7
+ "@helium/spl-utils": 0.9.14
"@helium/state-controller-sdk": ^0.0.13
- "@helium/sus": 0.9.7
+ "@helium/sus": 0.9.14
"@helium/transactions": 4.8.1
- "@helium/treasury-management-sdk": ^0.9.7
- "@helium/voter-stake-registry-hooks": 0.9.7
- "@helium/voter-stake-registry-sdk": 0.9.7
+ "@helium/treasury-management-sdk": ^0.9.14
+ "@helium/voter-stake-registry-hooks": 0.9.14
+ "@helium/voter-stake-registry-sdk": 0.9.14
"@helium/wallet-link": 4.11.0
"@jup-ag/api": ^6.0.6
"@keystonehq/keystone-sdk": ^0.8.0
@@ -12743,10 +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.26
"@onsol/tldparser": ^0.5.3
"@react-native-async-storage/async-storage": 1.18.1
"@react-native-community/blur": 4.3.0
@@ -12755,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
@@ -12765,7 +15157,8 @@ __metadata:
"@react-navigation/native-stack": 6.7.0
"@react-navigation/stack": 6.2.2
"@reduxjs/toolkit": 1.9.1
- "@shopify/restyle": 1.8.0
+ "@rnmapbox/maps": ^10.1.31
+ "@shopify/restyle": 2.4.2
"@solana/spl-account-compression": 0.1.4
"@solana/spl-memo": 0.2.3
"@solana/spl-token": 0.3.6
@@ -12845,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
@@ -12873,16 +15268,20 @@ __metadata:
react-error-boundary: ^4.0.13
react-i18next: 11.18.4
react-native: 0.74.5
+ react-native-animated-numbers: ^0.6.2
react-native-appstate-hook: 1.0.6
react-native-ble-plx: 2.0.3
react-native-charts-wrapper: 0.5.10
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
@@ -12893,13 +15292,13 @@ __metadata:
react-native-localize: 2.2.3
react-native-mail: 6.1.1
react-native-markdown-display: ^7.0.0-alpha.2
- react-native-navigation-bar-color: 2.0.2
+ react-native-navigation-bar-color: ^2.0.2
react-native-network-info: 5.2.1
react-native-onesignal: 5.2.2
react-native-os: ^1.2.6
react-native-pager-view: 6.1.2
react-native-permissions: ^3.9.0
- react-native-qrcode-svg: 6.1.2
+ react-native-qrcode-svg: ^6.3.2
react-native-randombytes: 3.6.1
react-native-reanimated: 3.14.0
react-native-safe-area-context: 4.10.8
@@ -12907,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
@@ -12918,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
@@ -13002,6 +15403,13 @@ __metadata:
languageName: node
linkType: hard
+"hi-base32@npm:^0.5.1":
+ version: 0.5.1
+ resolution: "hi-base32@npm:0.5.1"
+ checksum: 6655682b5796d75ed3068071e61d05a490e2086c4908af3b94a730059147b8a4a5e8870e656b828d0550dcc9988d8748bda54a53e428cbce28e0d7a785b2ffde
+ languageName: node
+ linkType: hard
+
"hmac-drbg@npm:^1.0.1":
version: 1.0.1
resolution: "hmac-drbg@npm:1.0.1"
@@ -13067,6 +15475,19 @@ __metadata:
languageName: node
linkType: hard
+"http-errors@npm:^1.7.2":
+ version: 1.8.1
+ resolution: "http-errors@npm:1.8.1"
+ dependencies:
+ depd: ~1.1.2
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: ">= 1.5.0 < 2"
+ toidentifier: 1.0.1
+ checksum: d3c7e7e776fd51c0a812baff570bdf06fe49a5dc448b700ab6171b1250e4cf7db8b8f4c0b133e4bfe2451022a5790c1ca6c2cae4094dedd6ac8304a1267f91d2
+ languageName: node
+ linkType: hard
+
"http-proxy-agent@npm:^7.0.0":
version: 7.0.2
resolution: "http-proxy-agent@npm:7.0.2"
@@ -13094,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:
@@ -13138,6 +15559,15 @@ __metadata:
languageName: node
linkType: hard
+"iconv-lite@npm:^0.4.24":
+ version: 0.4.24
+ resolution: "iconv-lite@npm:0.4.24"
+ dependencies:
+ safer-buffer: ">= 2.1.2 < 3"
+ checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6
+ languageName: node
+ linkType: hard
+
"iconv-lite@npm:^0.6.2":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
@@ -13193,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"
@@ -13203,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:
@@ -13213,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"
@@ -13291,6 +15735,29 @@ __metadata:
languageName: node
linkType: hard
+"inquirer@npm:^8.0.0, inquirer@npm:^8.2.0":
+ version: 8.2.6
+ resolution: "inquirer@npm:8.2.6"
+ dependencies:
+ ansi-escapes: ^4.2.1
+ chalk: ^4.1.1
+ cli-cursor: ^3.1.0
+ cli-width: ^3.0.0
+ external-editor: ^3.0.3
+ figures: ^3.0.0
+ lodash: ^4.17.21
+ mute-stream: 0.0.8
+ ora: ^5.4.1
+ run-async: ^2.4.0
+ rxjs: ^7.5.5
+ string-width: ^4.1.0
+ strip-ansi: ^6.0.0
+ through: ^2.3.6
+ wrap-ansi: ^6.0.1
+ checksum: 387ffb0a513559cc7414eb42c57556a60e302f820d6960e89d376d092e257a919961cd485a1b4de693dbb5c0de8bc58320bfd6247dfd827a873aa82a4215a240
+ languageName: node
+ linkType: hard
+
"internal-ip@npm:4.3.0":
version: 4.3.0
resolution: "internal-ip@npm:4.3.0"
@@ -13359,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"
@@ -13612,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"
@@ -13621,12 +16107,10 @@ __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
+"is-hex-prefixed@npm:1.0.0":
+ version: 1.0.0
+ resolution: "is-hex-prefixed@npm:1.0.0"
+ checksum: 5ac58e6e528fb029cc43140f6eeb380fad23d0041cc23154b87f7c9a1b728bcf05909974e47248fd0b7fcc11ba33cf7e58d64804883056fabd23e2b898be41de
languageName: node
linkType: hard
@@ -13653,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"
@@ -13749,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"
@@ -13813,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"
@@ -13820,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"
@@ -13855,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
@@ -13955,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"
@@ -14068,6 +16597,28 @@ __metadata:
languageName: node
linkType: hard
+"jayson@npm:^4.1.1":
+ version: 4.1.2
+ resolution: "jayson@npm:4.1.2"
+ dependencies:
+ "@types/connect": ^3.4.33
+ "@types/node": ^12.12.54
+ "@types/ws": ^7.4.4
+ JSONStream: ^1.3.5
+ commander: ^2.20.3
+ delay: ^5.0.0
+ es6-promisify: ^5.0.0
+ eyes: ^0.1.8
+ isomorphic-ws: ^4.0.1
+ json-stringify-safe: ^5.0.1
+ uuid: ^8.3.2
+ ws: ^7.5.10
+ bin:
+ jayson: bin/jayson.js
+ checksum: 10d6a0ce55045a1098b9b0d1d9b4b898f034e70696e57240ba76d67eddaabd703e1f59477c667b57e39f6f1fc54dbb87b1327a8a4edef39a37a17b70c79bb6e4
+ languageName: node
+ linkType: hard
+
"jest-changed-files@npm:^29.7.0":
version: 29.7.0
resolution: "jest-changed-files@npm:29.7.0"
@@ -14525,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"
@@ -14552,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"
@@ -14566,10 +17142,17 @@ __metadata:
languageName: node
linkType: hard
-"js-sha3@npm:^0.8.0":
+"js-sha3@npm:0.8.0, js-sha3@npm:^0.8.0":
+ version: 0.8.0
+ resolution: "js-sha3@npm:0.8.0"
+ checksum: 75df77c1fc266973f06cce8309ce010e9e9f07ec35ab12022ed29b7f0d9c8757f5a73e1b35aa24840dced0dea7059085aa143d817aea9e188e2a80d569d9adce
+ languageName: node
+ linkType: hard
+
+"js-sha512@npm:^0.8.0":
version: 0.8.0
- resolution: "js-sha3@npm:0.8.0"
- checksum: 75df77c1fc266973f06cce8309ce010e9e9f07ec35ab12022ed29b7f0d9c8757f5a73e1b35aa24840dced0dea7059085aa143d817aea9e188e2a80d569d9adce
+ resolution: "js-sha512@npm:0.8.0"
+ checksum: 32ca371ebd14c6c5c83360fd8b036cad2211537bef546b199ac8b901917299cab4c68f7f7c26ae72f836bbce0349cb463df9a62cdb4c90e38090fdb4db89ee87
languageName: node
linkType: hard
@@ -14592,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:
@@ -14702,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"
@@ -14711,6 +17303,15 @@ __metadata:
languageName: node
linkType: hard
+"json-bigint@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "json-bigint@npm:1.0.0"
+ dependencies:
+ bignumber.js: ^9.0.0
+ checksum: c67bb93ccb3c291e60eb4b62931403e378906aab113ec1c2a8dd0f9a7f065ad6fd9713d627b732abefae2e244ac9ce1721c7a3142b2979532f12b258634ce6f6
+ languageName: node
+ linkType: hard
+
"json-buffer@npm:3.0.1":
version: 3.0.1
resolution: "json-buffer@npm:3.0.1"
@@ -14788,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"
@@ -14797,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:
@@ -14880,6 +17491,18 @@ __metadata:
languageName: node
linkType: hard
+"keccak@npm:^3.0.2":
+ version: 3.0.4
+ resolution: "keccak@npm:3.0.4"
+ dependencies:
+ node-addon-api: ^2.0.0
+ node-gyp: latest
+ node-gyp-build: ^4.2.0
+ readable-stream: ^3.6.0
+ checksum: 2bf27b97b2f24225b1b44027de62be547f5c7326d87d249605665abd0c8c599d774671c35504c62c9b922cae02758504c6f76a73a84234d23af8a2211afaaa11
+ languageName: node
+ linkType: hard
+
"keymirror@npm:^0.1.1":
version: 0.1.1
resolution: "keymirror@npm:0.1.1"
@@ -15239,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"
@@ -15267,6 +17911,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.clonedeep@npm:^4.5.0":
+ version: 4.5.0
+ resolution: "lodash.clonedeep@npm:4.5.0"
+ checksum: 92c46f094b064e876a23c97f57f81fbffd5d760bf2d8a1c61d85db6d1e488c66b0384c943abee4f6af7debf5ad4e4282e74ff83177c9e63d8ff081a4837c3489
+ languageName: node
+ linkType: hard
+
"lodash.debounce@npm:^4.0.8":
version: 4.0.8
resolution: "lodash.debounce@npm:4.0.8"
@@ -15274,7 +17925,7 @@ __metadata:
languageName: node
linkType: hard
-"lodash.isequal@npm:4.5.0":
+"lodash.isequal@npm:4.5.0, lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
@@ -15288,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"
@@ -15302,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
@@ -15318,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:
@@ -15328,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"
@@ -15400,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"
@@ -15482,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
@@ -15662,6 +18341,31 @@ __metadata:
languageName: node
linkType: hard
+"merkletreejs@npm:^0.2.32":
+ version: 0.2.32
+ resolution: "merkletreejs@npm:0.2.32"
+ dependencies:
+ bignumber.js: ^9.0.1
+ buffer-reverse: ^1.0.1
+ crypto-js: ^3.1.9-1
+ treeify: ^1.1.0
+ web3-utils: ^1.3.4
+ checksum: 041b235adde94de584fdf5ef60138baca8d6f16bb48b3b7f714b607eaa76e4207ed5fef501ee5967371c56c5876804c4ff6da4705707f8cc0362d5c1e0358425
+ 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"
@@ -15951,6 +18655,13 @@ __metadata:
languageName: node
linkType: hard
+"micro-ftch@npm:^0.3.1":
+ version: 0.3.1
+ resolution: "micro-ftch@npm:0.3.1"
+ checksum: 0e496547253a36e98a83fb00c628c53c3fb540fa5aaeaf718438873785afd193244988c09d219bb1802984ff227d04938d9571ef90fe82b48bd282262586aaff
+ languageName: node
+ linkType: hard
+
"micromatch@npm:^3.1.10":
version: 3.1.10
resolution: "micromatch@npm:3.1.10"
@@ -15982,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"
@@ -16001,7 +18722,7 @@ __metadata:
languageName: node
linkType: hard
-"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.34":
+"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.34, mime-types@npm:~2.1.34":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
@@ -16028,6 +18749,15 @@ __metadata:
languageName: node
linkType: hard
+"mime@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "mime@npm:3.0.0"
+ bin:
+ mime: cli.js
+ checksum: f43f9b7bfa64534e6b05bd6062961681aeb406a5b53673b53b683f27fcc4e739989941836a355eef831f4478923651ecc739f4a5f6e20a76487b432bfd4db928
+ languageName: node
+ linkType: hard
+
"mimic-fn@npm:^1.0.0":
version: 1.2.0
resolution: "mimic-fn@npm:1.2.0"
@@ -16065,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:
@@ -16265,6 +18995,32 @@ __metadata:
languageName: node
linkType: hard
+"multistream@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "multistream@npm:4.1.0"
+ dependencies:
+ once: ^1.4.0
+ readable-stream: ^3.6.0
+ checksum: 305c49a1aadcb7f63f64d8ca2bb6e7852e5f7dba94c7329e9a72ce53cd0046686b71668dc1adbf123f17d2dd107765fc946e64c36a26b15c470a3146ea3bc923
+ languageName: node
+ linkType: hard
+
+"mustache@npm:^4.0.0":
+ version: 4.2.0
+ resolution: "mustache@npm:4.2.0"
+ bin:
+ mustache: bin/mustache
+ checksum: 928fcb63e3aa44a562bfe9b59ba202cccbe40a46da50be6f0dd831b495be1dd7e38ca4657f0ecab2c1a89dc7bccba0885eab7ee7c1b215830da765758c7e0506
+ languageName: node
+ linkType: hard
+
+"mute-stream@npm:0.0.8":
+ version: 0.0.8
+ resolution: "mute-stream@npm:0.0.8"
+ checksum: ff48d251fc3f827e5b1206cda0ffdaec885e56057ee86a3155e1951bc940fd5f33531774b1cc8414d7668c10a8907f863f6561875ee6e8768931a62121a531a1
+ languageName: node
+ linkType: hard
+
"mv@npm:~2":
version: 2.1.1
resolution: "mv@npm:2.1.1"
@@ -16338,6 +19094,48 @@ __metadata:
languageName: node
linkType: hard
+"near-api-js@npm:^0.44.2":
+ version: 0.44.2
+ resolution: "near-api-js@npm:0.44.2"
+ dependencies:
+ bn.js: 5.2.0
+ borsh: ^0.6.0
+ bs58: ^4.0.0
+ depd: ^2.0.0
+ error-polyfill: ^0.1.3
+ http-errors: ^1.7.2
+ js-sha256: ^0.9.0
+ mustache: ^4.0.0
+ node-fetch: ^2.6.1
+ text-encoding-utf-8: ^1.0.2
+ tweetnacl: ^1.0.1
+ checksum: d63625ab83d695d23a9126997355909fe141204c431a4818733050e1fcda11e5508dc70ff2e8fd55c1b2842908babd42fcf0ed4f3dc8c3fdb23ae422c497996d
+ languageName: node
+ linkType: hard
+
+"near-hd-key@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "near-hd-key@npm:1.2.1"
+ dependencies:
+ bip39: 3.0.2
+ create-hmac: 1.1.7
+ tweetnacl: 1.0.3
+ checksum: 7dc652952257407dfee5207df51173a37b09cde0d99966070e0de27aa7f8113f899e56338cfdae98e939a7541bfc25d79d1587df6154ee69d122b5ad919d0ff6
+ languageName: node
+ linkType: hard
+
+"near-seed-phrase@npm:^0.2.0":
+ version: 0.2.1
+ resolution: "near-seed-phrase@npm:0.2.1"
+ dependencies:
+ bip39-light: ^1.0.7
+ bs58: ^4.0.1
+ near-hd-key: ^1.2.1
+ tweetnacl: ^1.0.2
+ checksum: 3dda9211e76bac49dc90e21167c3224a5f49d357ab463ddd0eb89bdfc571b60d529a1bc88eb67b9d3bfe1bd9dfa5dea2f31a82f97c59909d2fd5106d6c2bffa0
+ languageName: node
+ linkType: hard
+
"negotiator@npm:0.6.3, negotiator@npm:^0.6.3":
version: 0.6.3
resolution: "negotiator@npm:0.6.3"
@@ -16513,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"
@@ -16575,6 +19382,25 @@ __metadata:
languageName: node
linkType: hard
+"number-to-bn@npm:1.7.0":
+ version: 1.7.0
+ resolution: "number-to-bn@npm:1.7.0"
+ dependencies:
+ bn.js: 4.11.6
+ strip-hex-prefix: 1.0.0
+ checksum: 5b8c9dbe7b49dc7a069e5f0ba4e197257c89db11463478cb002fee7a34dc8868636952bd9f6310e5fdf22b266e0e6dffb5f9537c741734718107e90ae59b3de4
+ languageName: node
+ linkType: hard
+
+"o3@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "o3@npm:1.0.3"
+ dependencies:
+ capability: ^0.2.5
+ checksum: 3b4d0686c94ac21b3c8bd66fb2c93a4daef7b8f52a20b04595754f8dc4102550de9a7b1cdffa3db2191d47a4ae70ca568f21d9f3ba29bb15c3f004dbf636c33c
+ languageName: node
+ linkType: hard
+
"ob1@npm:0.80.9":
version: 0.80.9
resolution: "ob1@npm:0.80.9"
@@ -16908,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"
@@ -16917,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"
@@ -16997,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"
@@ -17019,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"
@@ -17064,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"
@@ -17113,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"
@@ -17162,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"
@@ -17198,7 +20081,7 @@ __metadata:
languageName: node
linkType: hard
-"pbkdf2@npm:^3.0.3":
+"pbkdf2@npm:^3.0.3, pbkdf2@npm:^3.0.9":
version: 3.1.2
resolution: "pbkdf2@npm:3.1.2"
dependencies:
@@ -17301,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"
@@ -17664,7 +20554,7 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:*, prop-types@npm:^15.5.10, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
+"prop-types@npm:*, prop-types@npm:^15.5.10, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.0, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -17818,17 +20708,16 @@ __metadata:
languageName: node
linkType: hard
-"qrcode@npm:^1.5.0":
- version: 1.5.3
- resolution: "qrcode@npm:1.5.3"
+"qrcode@npm:^1.5.1":
+ version: 1.5.4
+ resolution: "qrcode@npm:1.5.4"
dependencies:
dijkstrajs: ^1.0.1
- encode-utf8: ^1.0.3
pngjs: ^5.0.0
yargs: ^15.3.1
bin:
qrcode: bin/qrcode
- checksum: 9a8a20a0a9cb1d15de8e7b3ffa214e8b6d2a8b07655f25bd1b1d77f4681488f84d7bae569870c0652872d829d5f8ac4922c27a6bd14c13f0e197bf07b28dead7
+ checksum: 0a162822e12c02b0333315462fd4ccad22255002130f86806773be7592aec5ef295efaffa3eb148cbf00e290839c7b610f63b0d62a0c5efc5bc52a68f4189684
languageName: node
linkType: hard
@@ -17950,7 +20839,7 @@ __metadata:
languageName: node
linkType: hard
-"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5":
+"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0":
version: 2.1.0
resolution: "randombytes@npm:2.1.0"
dependencies:
@@ -18087,6 +20976,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-animated-numbers@npm:^0.6.2":
+ version: 0.6.2
+ resolution: "react-native-animated-numbers@npm:0.6.2"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-native: ">=0.59"
+ checksum: 4a7e56bd06ac67e282633eeee7e0bcb836dd2e10d45e1e755b208bbb15c5fd4e111f9990669dfa288e88928adfbfe70a67a5ca1d9e864da22c3c87ed4f12263d
+ languageName: node
+ linkType: hard
+
"react-native-appstate-hook@npm:1.0.6":
version: 1.0.6
resolution: "react-native-appstate-hook@npm:1.0.6"
@@ -18142,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"
@@ -18216,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"
@@ -18345,7 +21268,7 @@ __metadata:
languageName: node
linkType: hard
-"react-native-navigation-bar-color@npm:2.0.2":
+"react-native-navigation-bar-color@npm:^2.0.2":
version: 2.0.2
resolution: "react-native-navigation-bar-color@npm:2.0.2"
checksum: 47b74fc343c63b90819a67889b7af6e9b6524a663586dc8a7927d81e8517fbf8b395545d651ddf44e978167e4d8994a4b6d6e3dc086a35903c48087fa40155cd
@@ -18401,17 +21324,18 @@ __metadata:
languageName: node
linkType: hard
-"react-native-qrcode-svg@npm:6.1.2":
- version: 6.1.2
- resolution: "react-native-qrcode-svg@npm:6.1.2"
+"react-native-qrcode-svg@npm:^6.3.2":
+ version: 6.3.2
+ resolution: "react-native-qrcode-svg@npm:6.3.2"
dependencies:
- prop-types: ^15.7.2
- qrcode: ^1.5.0
+ prop-types: ^15.8.0
+ qrcode: ^1.5.1
+ text-encoding: ^0.7.0
peerDependencies:
react: "*"
react-native: ">=0.63.4"
- react-native-svg: ^12.1.0
- checksum: 2e3150bf872a7c545527130dcca352c7d903df89d880333e0b046ef2079f5368d83a38df50f13b66ed9a52efdb5b90c7e027e3c96ce3e25ca3053996799d4826
+ react-native-svg: ">=13.2.0"
+ checksum: 17a2802583ef59c66cfb4d1f3c9c3304454baa345323ff8df9bfc24606e2c419cb7cadaccfca06a375261f03ff1a032fe5d4689d2cebceb0429e550a433d7fb7
languageName: node
linkType: hard
@@ -18491,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"
@@ -18620,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"
@@ -19045,14 +22001,39 @@ __metadata:
languageName: node
linkType: hard
-"regjsparser@npm:^0.9.1":
- version: 0.9.1
- resolution: "regjsparser@npm:0.9.1"
- dependencies:
- jsesc: ~0.5.0
- bin:
- regjsparser: bin/parser
- checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc
+"regjsparser@npm:^0.9.1":
+ version: 0.9.1
+ resolution: "regjsparser@npm:0.9.1"
+ dependencies:
+ jsesc: ~0.5.0
+ bin:
+ regjsparser: bin/parser
+ checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc
+ 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
@@ -19063,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"
@@ -19125,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"
@@ -19139,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"
@@ -19280,6 +22268,13 @@ __metadata:
languageName: node
linkType: hard
+"retry@npm:0.13.1":
+ version: 0.13.1
+ resolution: "retry@npm:0.13.1"
+ checksum: 47c4d5be674f7c13eee4cfe927345023972197dbbdfba5d3af7e461d13b44de1bfd663bfc80d2f601f8ef3fc8164c16dd99655a221921954a65d044a2fc1233b
+ languageName: node
+ linkType: hard
+
"retry@npm:^0.12.0":
version: 0.12.0
resolution: "retry@npm:0.12.0"
@@ -19434,6 +22429,35 @@ __metadata:
languageName: node
linkType: hard
+"rpc-websockets@npm:^9.0.2":
+ version: 9.0.4
+ resolution: "rpc-websockets@npm:9.0.4"
+ dependencies:
+ "@swc/helpers": ^0.5.11
+ "@types/uuid": ^8.3.4
+ "@types/ws": ^8.2.2
+ buffer: ^6.0.3
+ bufferutil: ^4.0.1
+ eventemitter3: ^5.0.1
+ utf-8-validate: ^5.0.2
+ uuid: ^8.3.2
+ ws: ^8.5.0
+ dependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: d5efe3a1e7fbd9858886342fb766c05ac69c645bfb3c39a907425163db33e237ae2a601b62e17451040584c06d8699152fb2311a7d6cded2a7e7d4e0e74f0c1a
+ languageName: node
+ linkType: hard
+
+"run-async@npm:^2.4.0":
+ version: 2.4.1
+ resolution: "run-async@npm:2.4.1"
+ checksum: a2c88aa15df176f091a2878eb840e68d0bdee319d8d97bbb89112223259cebecb94bc0defd735662b83c2f7a30bed8cddb7d1674eb48ae7322dc602b22d03797
+ languageName: node
+ linkType: hard
+
"run-parallel@npm:^1.1.2, run-parallel@npm:^1.1.9":
version: 1.2.0
resolution: "run-parallel@npm:1.2.0"
@@ -19461,6 +22485,15 @@ __metadata:
languageName: node
linkType: hard
+"rxjs@npm:^7.5.5":
+ version: 7.8.1
+ resolution: "rxjs@npm:7.8.1"
+ dependencies:
+ tslib: ^2.1.0
+ checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119
+ languageName: node
+ linkType: hard
+
"safe-array-concat@npm:^1.0.0, safe-array-concat@npm:^1.1.2":
version: 1.1.2
resolution: "safe-array-concat@npm:1.1.2"
@@ -19537,7 +22570,7 @@ __metadata:
languageName: node
linkType: hard
-"safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.1.0":
+"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.1.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0
@@ -19577,7 +22610,21 @@ __metadata:
languageName: node
linkType: hard
-"secp256k1@npm:^4.0.0":
+"scrypt-js@npm:3.0.1":
+ version: 3.0.1
+ resolution: "scrypt-js@npm:3.0.1"
+ checksum: b7c7d1a68d6ca946f2fbb0778e0c4ec63c65501b54023b2af7d7e9f48fdb6c6580d6f7675cd53bda5944c5ebc057560d5a6365079752546865defb3b79dea454
+ 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"
dependencies:
@@ -19674,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"
@@ -19916,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"
@@ -19975,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"
@@ -20207,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"
@@ -20279,7 +23364,7 @@ __metadata:
languageName: node
linkType: hard
-"statuses@npm:~1.5.0":
+"statuses@npm:>= 1.5.0 < 2, statuses@npm:~1.5.0":
version: 1.5.0
resolution: "statuses@npm:1.5.0"
checksum: c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c
@@ -20310,6 +23395,13 @@ __metadata:
languageName: node
linkType: hard
+"stream-transform@npm:^3.3.2":
+ version: 3.3.2
+ resolution: "stream-transform@npm:3.3.2"
+ checksum: 5aa088f8ed92de8c396cb6f942a1ae01321c6675ba4a103a5025bb397364161475bc50e90cbf858625ecf2bb694078ea79cd1282e5e2f87164c19fa4aaeeefd0
+ languageName: node
+ linkType: hard
+
"stream@npm:0.0.2":
version: 0.0.2
resolution: "stream@npm:0.0.2"
@@ -20319,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"
@@ -20326,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"
@@ -20516,6 +23622,15 @@ __metadata:
languageName: node
linkType: hard
+"strip-hex-prefix@npm:1.0.0":
+ version: 1.0.0
+ resolution: "strip-hex-prefix@npm:1.0.0"
+ dependencies:
+ is-hex-prefixed: 1.0.0
+ checksum: 4cafe7caee1d281d3694d14920fd5d3c11adf09371cef7e2ccedd5b83efd9e9bd2219b5d6ce6e809df6e0f437dc9d30db1192116580875698aad164a6d6b285b
+ languageName: node
+ linkType: hard
+
"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1":
version: 3.1.1
resolution: "strip-json-comments@npm:3.1.1"
@@ -20597,6 +23712,13 @@ __metadata:
languageName: node
linkType: hard
+"superstruct@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "superstruct@npm:2.0.2"
+ checksum: a5f75b72cb8b14b86f4f7f750dae8c5ab0e4e1d92414b55e7625bae07bbcafad81c92486e7e32ccacd6ae1f553caff2b92a50ff42ad5093fd35b9cb7f4e5ec86
+ languageName: node
+ linkType: hard
+
"supports-color@npm:^5.3.0":
version: 5.5.0
resolution: "supports-color@npm:5.5.0"
@@ -20671,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"
@@ -20803,6 +23934,13 @@ __metadata:
languageName: node
linkType: hard
+"text-encoding@npm:^0.7.0":
+ version: 0.7.0
+ resolution: "text-encoding@npm:0.7.0"
+ checksum: b6109a843fb1b8748b32e1ecd6df74d370f46c13ac136bcb6ca15db70209bb0b8ec1f296ebb4b0dd9961150e205dcc044b89f8cf7657f6faef78c7569a2a81bc
+ languageName: node
+ linkType: hard
+
"text-table@npm:^0.2.0":
version: 0.2.0
resolution: "text-table@npm:0.2.0"
@@ -20863,7 +24001,7 @@ __metadata:
languageName: node
linkType: hard
-"through@npm:2, through@npm:>=2.2.7 <3":
+"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
@@ -20886,6 +24024,24 @@ __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"
+ dependencies:
+ tmp: ^0.2.0
+ checksum: f854f5307dcee6455927ec3da9398f139897faf715c5c6dcee6d9471ae85136983ea06662eba2edf2533bdcb0fca66d16648e79e14381e30c7fb20be9c1aa62c
+ languageName: node
+ linkType: hard
+
"tmp@npm:^0.0.33":
version: 0.0.33
resolution: "tmp@npm:0.0.33"
@@ -20895,6 +24051,13 @@ __metadata:
languageName: node
linkType: hard
+"tmp@npm:^0.2.0":
+ version: 0.2.3
+ resolution: "tmp@npm:0.2.3"
+ checksum: 73b5c96b6e52da7e104d9d44afb5d106bb1e16d9fa7d00dbeb9e6522e61b571fbdb165c756c62164be9a3bbe192b9b268c236d370a2a0955c7689cd2ae377b95
+ languageName: node
+ linkType: hard
+
"tmpl@npm:1.0.5":
version: 1.0.5
resolution: "tmpl@npm:1.0.5"
@@ -20991,6 +24154,13 @@ __metadata:
languageName: node
linkType: hard
+"treeify@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "treeify@npm:1.1.0"
+ checksum: aa00dded220c1dd052573bd6fc2c52862f09870851a284f0d3650d72bf913ba9b4f6b824f4f1ab81899bae29375f4266b07fe47cbf82343a1efa13cc09ce87af
+ languageName: node
+ linkType: hard
+
"ts-api-utils@npm:^1.3.0":
version: 1.3.0
resolution: "ts-api-utils@npm:1.3.0"
@@ -21007,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"
@@ -21084,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"
@@ -21102,7 +24300,7 @@ __metadata:
languageName: node
linkType: hard
-"tweetnacl@npm:1.0.3, tweetnacl@npm:^1.0.3":
+"tweetnacl@npm:1.0.3, tweetnacl@npm:^1.0.1, tweetnacl@npm:^1.0.2, tweetnacl@npm:^1.0.3":
version: 1.0.3
resolution: "tweetnacl@npm:1.0.3"
checksum: e4a57cac188f0c53f24c7a33279e223618a2bfb5fea426231991652a13247bea06b081fd745d71291fcae0f4428d29beba1b984b1f1ce6f66b06a6d1ab90645c
@@ -21260,6 +24458,13 @@ __metadata:
languageName: node
linkType: hard
+"u3@npm:^0.1.1":
+ version: 0.1.1
+ resolution: "u3@npm:0.1.1"
+ checksum: d55f396c607b0a2340d6165526b5143a29b369e7e0397b04f79633db77cd668f2da713feb7adb4f93a588e82a388ff995d9a2b16123d0cb02fe394fd2f26b529
+ languageName: node
+ linkType: hard
+
"ua-parser-js@npm:^0.7.30":
version: 0.7.36
resolution: "ua-parser-js@npm:0.7.36"
@@ -21311,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"
@@ -21418,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"
@@ -21456,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"
@@ -21489,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"
@@ -21533,6 +24793,13 @@ __metadata:
languageName: node
linkType: hard
+"utf8@npm:3.0.0":
+ version: 3.0.0
+ resolution: "utf8@npm:3.0.0"
+ checksum: cb89a69ad9ab393e3eae9b25305b3ff08bebca9adc839191a34f90777eb2942f86a96369d2839925fea58f8f722f7e27031d697f10f5f39690f8c5047303e62d
+ languageName: node
+ linkType: hard
+
"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"
@@ -21676,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"
@@ -21690,6 +24964,13 @@ __metadata:
languageName: node
linkType: hard
+"vlq@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "vlq@npm:2.0.4"
+ checksum: b2ed0d3a5423f34bba98a18250f8b13a96eebff9c8f9427fa9cd78065d31f35641f6fd659c5642253b79532000a37aec0582abac95d1ef4af2cd0c96a716f1b6
+ languageName: node
+ linkType: hard
+
"vm-browserify@npm:0.0.4":
version: 0.0.4
resolution: "vm-browserify@npm:0.0.4"
@@ -21731,6 +25012,22 @@ __metadata:
languageName: node
linkType: hard
+"web3-utils@npm:^1.3.4":
+ version: 1.10.4
+ resolution: "web3-utils@npm:1.10.4"
+ dependencies:
+ "@ethereumjs/util": ^8.1.0
+ bn.js: ^5.2.1
+ ethereum-bloom-filters: ^1.0.6
+ ethereum-cryptography: ^2.1.2
+ ethjs-unit: 0.1.6
+ number-to-bn: 1.7.0
+ randombytes: ^2.1.0
+ utf8: 3.0.0
+ checksum: a1535817a4653f1b5cc868aa19305158122379078a41e13642e1ba64803f6f8e5dd2fb8c45c033612b8f52dde42d8008afce85296c0608276fe1513dece66a49
+ languageName: node
+ linkType: hard
+
"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"
@@ -21905,7 +25202,7 @@ __metadata:
languageName: node
linkType: hard
-"wrap-ansi@npm:^6.2.0":
+"wrap-ansi@npm:^6.0.1, wrap-ansi@npm:^6.2.0":
version: 6.2.0
resolution: "wrap-ansi@npm:6.2.0"
dependencies:
@@ -21955,6 +25252,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:7.4.6":
+ version: 7.4.6
+ resolution: "ws@npm:7.4.6"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 3a990b32ed08c72070d5e8913e14dfcd831919205be52a3ff0b4cdd998c8d554f167c9df3841605cde8b11d607768cacab3e823c58c96a5c08c987e093eb767a
+ languageName: node
+ linkType: hard
+
"ws@npm:^6.2.2":
version: 6.2.2
resolution: "ws@npm:6.2.2"
@@ -21979,6 +25291,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:^7.5.10":
+ version: 7.5.10
+ resolution: "ws@npm:7.5.10"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: f9bb062abf54cc8f02d94ca86dcd349c3945d63851f5d07a3a61c2fcb755b15a88e943a63cf580cbdb5b74436d67ef6b67f745b8f7c0814e411379138e1863cb
+ languageName: node
+ linkType: hard
+
"ws@npm:^8.12.1, ws@npm:^8.5.0":
version: 8.14.2
resolution: "ws@npm:8.14.2"
@@ -21994,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"
@@ -22004,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"
@@ -22114,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"
@@ -22123,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"
@@ -22159,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: