diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee4344c..05c8cad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,26 +2,45 @@
> This changelog keeps track of all updates and improvements made to `W3sSampleWallet`.
+## v2.1.0 - _(2026-04-13)_
+
+### ๐ What's New
+
+- Bumped `@circle-fin/w3s-pw-react-native-sdk` to **v2.2.1** [(npm)](https://www.npmjs.com/package/@circle-fin/w3s-pw-react-native-sdk); bumped app metadata to **2.1.0**.
+- Updated README for **iOS/Android** requirements aligned with SDK **2.2.1** (including **Android SDK Platform 36** where applicable).
+- Fixed **iOS tab switching** when using `react-native-collapsible-tab-view` v8 with React Native **0.81**.
+- Added **AGENTS.md** with local verification steps for contributors and agents.
+- CI: **ESLint**, **Prettier**, and **TypeScript** (`tsc --noEmit`) on pull requests; **AI PR** optional review workflow; internal **quality-checks** wired for **Cloudsmith** auth during `npm ci`.
+- Dependency and security-related upgrades, including **tar**, **minimatch**, **picomatch**, **undici**, **node-forge**, **flatted**, and **brace-expansion** (addressing reported advisories).
+
## v2.0.0 - _(2026-03-10)_
+
### ๐ What's New
+
- Migrated from **bare React Native** to **Expo 54**
- Upgraded `@circle-fin/w3s-pw-react-native-sdk` from v1 to v2
- Updated README with configuration details
- Added MIGRATION_GUIDE
## v1.1.6 - _(2026-03-06)_
+
### ๐ What's New
+
- Bumped `@circle-fin/w3s-pw-react-native-sdk` to v1.1.7 [(npm)](https://www.npmjs.com/package/@circle-fin/w3s-pw-react-native-sdk)
- Upgraded dependencies and improved SDK integration.
## v1.1.2 - _(2025-03-19)_
+
### ๐ What's New
+
- Upgrade React Native version from _0.73.6_ to _0.75.5_.
- Recommended upgrade to `w3s-react-native-sdk` v1.1.2 [(npm)](https://www.npmjs.com/package/@circle-fin/w3s-pw-react-native-sdk)
- Upgraded dependencies and improved SDK integration.
## v1.0.1 - _(2024-09-04)_
+
### ๐ Initial Release
+
- First official release of `W3sSampleWallet`.
- Example project included to demonstrate SDK integration.
- Integrated with `w3s-react-native-sdk` v1.1.1 [(npm)](https://www.npmjs.com/package/@circle-fin/w3s-pw-react-native-sdk).
diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index 0b7b4ce..b28cb57 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -12,17 +12,18 @@ If you have an existing bare React Native project using SDK v1 and want to upgra
- [Path 2: Migrate to Expo-Managed Workflow](#path-2-migrate-to-expo-managed-workflow)
- [API Changes](#api-changes)
-
---
### Understanding the Architecture Change
**SDK v1**: Traditional bare React Native architecture
+
- Package: `"@circle-fin/w3s-pw-react-native-sdk": "^1.0.0"`
- Architecture: Bare React Native
- Build: Manual native project setup
**SDK v2**: Expo Modules architecture
+
- Package: `"@circle-fin/w3s-pw-react-native-sdk": "^2.0.0"`
- Architecture: Expo Modules
- Build: Expo Prebuild
@@ -43,11 +44,13 @@ Choose the migration path based on your project's native code customizations:
This approach preserves your existing native projects and adds Expo Modules support to them.
**Best for:**
+
- Projects with **custom native code** (native modules, custom configurations, etc.)
- Teams that want to **continue managing** `ios/` and `android/` directories manually
- Minimal changes to existing workflow
**How it works:**
+
- Uses `npx install-expo-modules@latest` to automatically configure native projects
- Keeps your existing `ios/` and `android/` directories
- Adds necessary Expo Modules configuration without removing customizations
@@ -76,11 +79,13 @@ npm install @circle-fin/w3s-pw-react-native-sdk@^2.0.0
4. **Build and test:**
For iOS:
+
```bash
npm run ios
```
For Android:
+
```bash
npm run android
```
@@ -92,11 +97,13 @@ npm run android
This approach converts your project to use Expo's managed workflow where `expo prebuild` generates and manages native code.
**Best for:**
+
- Projects with **minimal or no custom native code**
- Teams that want **Expo to manage** native configurations
- Simpler maintenance through declarative `app.json` configuration
**How it works:**
+
- Deletes and regenerates `ios/` and `android/` directories from `app.json`
- Native code is managed by Expo (don't edit directly)
- Run `expo prebuild` whenever you change native configuration
@@ -146,11 +153,13 @@ The `--clean` flag will delete and regenerate the native directories.
5. **Build and test:**
For iOS:
+
```bash
npx expo run:ios
```
For Android:
+
```bash
npx expo run:android
```
@@ -167,31 +176,34 @@ npx expo run:android
**Add listener:**
SDK v1:
+
```typescript
WalletSdk.addListener((event) => {
// Handle event
-})
+});
```
SDK v2:
+
```typescript
const eventListener = ProgrammablewalletRnSdk.addListener(
- 'CirclePwOnEvent',
+ "CirclePwOnEvent",
(event) => {
// Handle event
- }
-)
+ },
+);
```
**Remove listener:**
SDK v1:
+
```typescript
-WalletSdk.removeAllListeners()
+WalletSdk.removeAllListeners();
```
SDK v2:
+
```typescript
-eventListener.remove()
+eventListener.remove();
```
-
diff --git a/README.md b/README.md
index 2c2f711..507df2f 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,16 @@ This sample app supports three authentication methods:
### 1. PIN Code (Recommended for quick start)
+
- **Simplest setup** - Only requires Circle App ID
### 2. Email OTP
+
- **Backend configuration** - Requires email service setup on Circle developer console
- No additional client-side configuration needed
### 3. Social Login (Google, Facebook, Apple)
+
- **Advanced setup** - Requires OAuth provider accounts and platform-specific configuration
- Additional setup for iOS and Android
@@ -33,22 +36,25 @@ This sample app supports three authentication methods:
## Requirements
### Development Environment
+
- Node.js 20.19.4 or higher
- npm
- Expo CLI
### Android
+
- Java 17 (JDK 17 recommended)
- Android Studio and Android SDK
-- Android SDK Platform 35 (Android 15 VanillaIceCream)
+- Android SDK Platform 36 (Android 16 Baklava)
- Android SDK Build-Tools 36.0.0
-- Android device or emulator (API level 35+)
+- Android device or emulator (API level 36+)
### iOS
-- macOS with Xcode 16.1+ (Xcode 26 is recommended)
+
+- macOS with Xcode 16.3+ (Xcode 26 is recommended)
- Xcode Command Line Tools
- CocoaPods
-- iOS device (iOS 15.0+) or Simulator
+- iOS device (iOS 15.1+) or Simulator
- Apple Developer account (for physical device testing)
---
@@ -56,6 +62,7 @@ This sample app supports three authentication methods:
## Quick Start (PIN Mode)
### Prerequisites
+
1. **Circle Developer Console Account** - [Sign up here](https://console.circle.com)
2. **App ID** - Get from [Circle Developer Console](https://console.circle.com/wallets/user/configurator) โ Wallets โ User Controlled โ Configurator
3. **GitHub PAT** (Android only) - [Create token](https://github.com/settings/tokens) with `read:packages` permission
@@ -95,11 +102,13 @@ npx expo prebuild
**Step 5: Run the app**
For iOS:
+
```bash
npm run ios
```
For Android:
+
```bash
npm run android
```
@@ -123,6 +132,7 @@ Email OTP authentication requires an SMTP email service configured on your backe
Follow [our tutorial](https://developers.circle.com/wallets/user-controlled/create-user-wallets-with-email#step-1-get-mailtrap-smtp-credentials) to configure your SMTP credentials. The tutorial uses [Mailtrap](https://mailtrap.io/) for testing.
The tutorial covers:
+
- **Step 1:** Getting SMTP credentials from your email provider
- **Step 2:** Configuring SMTP settings in Circle Developer Console
@@ -146,6 +156,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
Google
**What you need:**
+
- Web Client ID
- `google-services.json` file from Firebase (for Android)
- iOS Client ID (extracted from `GoogleService-Info.plist`)
@@ -159,9 +170,9 @@ Before configuring your app, you need to obtain IDs from each social provider.
- Click "Add app" โ Select Android
- Package name: `com.circle.w3s.rn.sample.wallet`
- Download the `google-services.json` file
-
- For detailed Android setup steps, see [Firebase Android setup guide](https://firebase.google.com/docs/android/setup#create-firebase-project)
-
+
+ For detailed Android setup steps, see [Firebase Android setup guide](https://firebase.google.com/docs/android/setup#create-firebase-project)
+
3. Add an **iOS app** to your project:
- Go to Project Settings โ Your apps
- Click "Add app" โ Select iOS
@@ -178,6 +189,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
- In the **Web SDK configuration** panel, copy the **Web client ID**
**Save these values:**
+
```
โ Web Client ID: xxxxx.apps.googleusercontent.com
โ google-services.json: Downloaded
@@ -190,6 +202,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
Facebook
**What you need:**
+
- Facebook App ID
- Facebook Client Token
- Facebook Display Name
@@ -205,6 +218,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
- **Facebook Display Name** (your app name)
**Save these values:**
+
```
โ Facebook App ID: xxxxxxxxxxxx
โ Facebook Client Token: xxxxxxxxxxxxxxxx
@@ -217,6 +231,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
Apple
**What you need:**
+
- Service ID (for Sign in with Apple on Android)
**Steps:**
@@ -225,6 +240,7 @@ Before configuring your app, you need to obtain IDs from each social provider.
2. Note down your **Service ID**
**Save this value:**
+
```
โ Apple Service ID: com.yourcompany.yourapp
```
@@ -311,6 +327,7 @@ Edit `prebuild-sync-src/android/app/src/main/res/values/strings.xml`:
```
Replace:
+
- `YOUR_FACEBOOK_APP_ID` with your Facebook App ID
- `YOUR_FACEBOOK_CLIENT_TOKEN` with your Facebook Client Token
@@ -340,6 +357,7 @@ Replace `YOUR_APPLE_SERVICE_ID` with your Apple Service ID (e.g., `com.yourcompa
If you encounter build or Metro bundler errors:
1. **Clean install and rebuild:**
+
```sh
rm -rf node_modules package-lock.json android ios .expo
npm install
@@ -347,6 +365,7 @@ If you encounter build or Metro bundler errors:
```
2. **Clear Metro bundler cache:**
+
```sh
npx expo start --clear
```
diff --git a/SECURITY.md b/SECURITY.md
index 014997a..bf0c437 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,4 +2,4 @@
## Reporting a Vulnerability
-Please do not file public issues on Github for security vulnerabilities. All security vulnerabilities should be reported to Circle privately, through Circle's [Vulnerability Disclosure Program](https://hackerone.com/circle). Please read through the program policy before submitting a report.
\ No newline at end of file
+Please do not file public issues on GitHub for security vulnerabilities. All security vulnerabilities should be reported to Circle privately, through Circle's [Vulnerability Disclosure Program](https://hackerone.com/circle). Please read through the program policy before submitting a report.
diff --git a/app/ExecuteScreen.tsx b/app/ExecuteScreen.tsx
index ff58021..350f83f 100644
--- a/app/ExecuteScreen.tsx
+++ b/app/ExecuteScreen.tsx
@@ -16,104 +16,133 @@
* limitations under the License.
*/
-import * as React from "react"
-import { Text, View, ScrollView, Image, TouchableOpacity, StyleSheet } from "react-native"
-import { SafeAreaView } from "react-native-safe-area-context"
-import { colors, commonStyles } from "../styles"
-import { useTranslation } from 'react-i18next'
-import { MainButton } from "../components/MainButton"
-import { AuthMode } from "../redux/types"
-import CommonInputText from "../components/CommonInputText"
-import useWalletSdk from "../utils/useWalletSdk"
-import { useSnackBar } from "../utils/useSnackBar"
-import CopyableText from "../components/CopyableText"
-import RequiredMarkText from "../components/RequiredMarkText"
-import { useRouter, useLocalSearchParams } from "expo-router"
-import { SnackBar } from "../components/SnackBar"
-import { useSelector } from "react-redux"
+import * as React from "react";
+import {
+ Text,
+ View,
+ ScrollView,
+ Image,
+ TouchableOpacity,
+ StyleSheet,
+} from "react-native";
+import { SafeAreaView } from "react-native-safe-area-context";
+import { colors, commonStyles } from "../styles";
+import { useTranslation } from "react-i18next";
+import { MainButton } from "../components/MainButton";
+import { AuthMode } from "../redux/types";
+import CommonInputText from "../components/CommonInputText";
+import useWalletSdk from "../utils/useWalletSdk";
+import { useSnackBar } from "../utils/useSnackBar";
+import CopyableText from "../components/CopyableText";
+import RequiredMarkText from "../components/RequiredMarkText";
+import { useRouter, useLocalSearchParams } from "expo-router";
+import { SnackBar } from "../components/SnackBar";
+import { useSelector } from "react-redux";
import {
selectEmailEncryptionKey,
selectEmailUserToken,
selectSocialEncryptionKey,
- selectSocialUserToken
-} from "../features/result/resultSlice"
+ selectSocialUserToken,
+} from "../features/result/resultSlice";
export default function ExecuteScreen() {
- const { t } = useTranslation()
- const [challengeId, setChallengeId] = React.useState("")
- const { visible, message, isSuccess, showSnackBar, hideSnackBar } = useSnackBar()
- const { execute } = useWalletSdk(showSnackBar)
- const router = useRouter()
- const params = useLocalSearchParams()
-
+ const { t } = useTranslation();
+ const [challengeId, setChallengeId] = React.useState("");
+ const { visible, message, isSuccess, showSnackBar, hideSnackBar } =
+ useSnackBar();
+ const { execute } = useWalletSdk(showSnackBar);
+ const router = useRouter();
+ const params = useLocalSearchParams();
+
// Get authMode from route parameters
- const authMode = params.authMode as AuthMode || AuthMode.social
-
+ const authMode = (params.authMode as AuthMode) || AuthMode.social;
+
// Use Redux selectors to get tokens and keys
- const socialUserToken = useSelector(selectSocialUserToken)
- const socialEncryptionKey = useSelector(selectSocialEncryptionKey)
- const emailUserToken = useSelector(selectEmailUserToken)
- const emailEncryptionKey = useSelector(selectEmailEncryptionKey)
-
+ const socialUserToken = useSelector(selectSocialUserToken);
+ const socialEncryptionKey = useSelector(selectSocialEncryptionKey);
+ const emailUserToken = useSelector(selectEmailUserToken);
+ const emailEncryptionKey = useSelector(selectEmailEncryptionKey);
+
// Determine which token and key to use based on authMode
- const userToken = authMode === AuthMode.social ? socialUserToken : emailUserToken
- const encryptionKey = authMode === AuthMode.social ? socialEncryptionKey : emailEncryptionKey
-
+ const userToken =
+ authMode === AuthMode.social ? socialUserToken : emailUserToken;
+ const encryptionKey =
+ authMode === AuthMode.social ? socialEncryptionKey : emailEncryptionKey;
+
// Component to display values
- const ValueComponent = (value: string | undefined | null, accessibilityLabel: string) => {
+ const ValueComponent = (
+ value: string | undefined | null,
+ accessibilityLabel: string,
+ ) => {
if (value) {
return (
+ style={[commonStyles.normalValueText]}
+ >
{value}
- )
+ );
}
- return null
- }
-
+ return null;
+ };
+
return (
{
- router.back()
- }}>
-
+ router.back();
+ }}
+ >
+
-
- {t('go_execute_bt')}
-
+
+ {t("go_execute_bt")}
+
{t("encryption_title")}
{ValueComponent(encryptionKey, `executeEncryptionKey`)}
-
+
{t("user_token_title")}
-
-
-
+
+
+
-
+
{
if (userToken && encryptionKey) {
- execute(userToken, encryptionKey, challengeId, result => {
- showSnackBar(t('execute_success'), true)
- if (__DEV__) {
- console.log(JSON.stringify(result))
- }
- }, e => {
- showSnackBar(e.message, false)
- })
+ execute(
+ userToken,
+ encryptionKey,
+ challengeId,
+ (result) => {
+ showSnackBar(t("execute_success"), true);
+ if (__DEV__) {
+ console.log(JSON.stringify(result));
+ }
+ },
+ (e) => {
+ showSnackBar(e?.message || "Unknown error", false);
+ },
+ );
}
}}
disabled={challengeId.length === 0 || !userToken || !encryptionKey}
@@ -127,7 +156,7 @@ export default function ExecuteScreen() {
onDismiss={hideSnackBar}
/>
- )
+ );
}
const styles = StyleSheet.create({
@@ -135,7 +164,7 @@ const styles = StyleSheet.create({
color: colors.execute_challenge_screen_title,
fontWeight: "700",
fontSize: 22,
- textAlign: 'center',
- marginBottom: 8
+ textAlign: "center",
+ marginBottom: 8,
},
-})
\ No newline at end of file
+});
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 354df11..43565d5 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -16,69 +16,78 @@
* limitations under the License.
*/
-import FontAwesome from '@expo/vector-icons/FontAwesome'
-import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
-import { useFonts } from 'expo-font'
-import { Stack } from 'expo-router'
-import * as SplashScreen from 'expo-splash-screen'
-import { SafeAreaProvider } from 'react-native-safe-area-context'
-import { useEffect } from 'react'
-import { useColorScheme } from 'react-native'
-import { Provider } from 'react-redux'
-import { store } from '../redux/store'
-import { GestureHandlerRootView } from 'react-native-gesture-handler'
-import '../utils/i18n'
+import FontAwesome from "@expo/vector-icons/FontAwesome";
+import {
+ DarkTheme,
+ DefaultTheme,
+ ThemeProvider,
+} from "@react-navigation/native";
+import { useFonts } from "expo-font";
+import { Stack } from "expo-router";
+import * as SplashScreen from "expo-splash-screen";
+import { SafeAreaProvider } from "react-native-safe-area-context";
+import { useEffect } from "react";
+import { useColorScheme } from "react-native";
+import { Provider } from "react-redux";
+import { store } from "../redux/store";
+import { GestureHandlerRootView } from "react-native-gesture-handler";
+import "../utils/i18n";
export {
// Catch any errors thrown by the Layout component.
- ErrorBoundary
-} from 'expo-router'
+ ErrorBoundary,
+} from "expo-router";
export const unstable_settings = {
- initialRouteName: 'index',
-}
+ initialRouteName: "index",
+};
// Prevent the splash screen from auto-hiding before asset loading is complete.
-SplashScreen.preventAutoHideAsync()
+SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
...FontAwesome.font,
- })
+ });
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
- if (error) throw error
- }, [error])
+ if (error) throw error;
+ }, [error]);
useEffect(() => {
if (loaded) {
- SplashScreen.hideAsync()
+ SplashScreen.hideAsync();
}
- }, [loaded])
+ }, [loaded]);
if (!loaded) {
- return null
+ return null;
}
- return
+ return ;
}
function RootLayoutNav() {
- const colorScheme = useColorScheme()
+ const colorScheme = useColorScheme();
return (
-
+
-
+
- )
-}
\ No newline at end of file
+ );
+}
diff --git a/app/index.tsx b/app/index.tsx
index cc2e464..d55eb49 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -16,89 +16,92 @@
* limitations under the License.
*/
-import * as React from "react"
-import { StyleSheet, Text, View, Keyboard } from "react-native"
-import { SafeAreaView } from "react-native-safe-area-context"
-import { useTranslation } from "react-i18next"
-import { colors, commonStyles } from "../styles"
-import { useEffect, useState } from "react"
-import { DefaultCustomizer } from "../customize/DefaultCustomizer"
-import { useSnackBar } from "../utils/useSnackBar"
-import { MaterialTabBar, MaterialTabBarProps, Tabs } from 'react-native-collapsible-tab-view'
-import ProgrammablewalletRnSdk, { WalletSdk } from "@circle-fin/w3s-pw-react-native-sdk"
-import { SnackBar } from "../components/SnackBar"
-import { useRouter } from "expo-router"
-import { PinTab } from "../components/PinTab"
-import { EmailTab } from "../components/EmailTab"
-import { SocialTab } from "../components/SocialTab"
-
-const TAB_BAR_HEIGHT = 48
+import * as React from "react";
+import { StyleSheet, Text, View, Keyboard } from "react-native";
+import { SafeAreaView } from "react-native-safe-area-context";
+import { useTranslation } from "react-i18next";
+import { colors, commonStyles } from "../styles";
+import { useCallback, useEffect } from "react";
+import { DefaultCustomizer } from "../customize/DefaultCustomizer";
+import { useSnackBar } from "../utils/useSnackBar";
+import {
+ MaterialTabBar,
+ MaterialTabBarProps,
+ Tabs,
+} from "react-native-collapsible-tab-view";
+import ProgrammablewalletRnSdk, {
+ WalletSdk,
+} from "@circle-fin/w3s-pw-react-native-sdk";
+import { SnackBar } from "../components/SnackBar";
+import { PinTab } from "../components/PinTab";
+import { EmailTab } from "../components/EmailTab";
+import { SocialTab } from "../components/SocialTab";
export default function IndexScreen() {
- const { t } = useTranslation()
- const { visible, message, isSuccess, showSnackBar, hideSnackBar } = useSnackBar()
- const router = useRouter()
-
- // Initialize headerHeight state with the default value, will be updated dynamically
- const [headerHeight, setHeaderHeight] = useState(TAB_BAR_HEIGHT)
+ const { t } = useTranslation();
+ const { visible, message, isSuccess, showSnackBar, hideSnackBar } =
+ useSnackBar();
useEffect(() => {
- DefaultCustomizer.setup()
+ DefaultCustomizer.setup();
try {
const eventListener = ProgrammablewalletRnSdk.addListener(
- 'CirclePwOnEvent',
+ "CirclePwOnEvent",
(event) => {
- console.log(event)
+ console.log(event);
// Bring application to foreground
- WalletSdk.moveRnTaskToFront()
+ WalletSdk.moveRnTaskToFront();
// Dismiss keyboard to prevent it from blocking the snackbar
- Keyboard.dismiss()
+ Keyboard.dismiss();
// Format event content for display
- const eventMessage = `CirclePwOnEvent: ${JSON.stringify(event)}`
- showSnackBar(eventMessage, true)
- }
- )
-
+ const eventMessage = `CirclePwOnEvent: ${JSON.stringify(event)}`;
+ showSnackBar(eventMessage, true);
+ },
+ );
+
// Cleanup function
return () => {
// Remove the specific listener
- eventListener.remove()
- }
+ eventListener.remove();
+ };
} catch (error) {
- console.log("Error setting up SDK listeners:", error)
+ console.error("Error setting up SDK listeners:", error);
+ showSnackBar(
+ "Failed to initialize wallet SDK event listener. Please restart the app.",
+ false,
+ );
}
- }, [showSnackBar, t])
+ }, [showSnackBar]);
- const header = () => {
- return (
- (
+ {
- // Dynamically measure the height of the header content
- const { height } = event.nativeEvent.layout;
- setHeaderHeight(height);
+ alignItems: "center",
+ justifyContent: "center",
+ width: "100%",
}}
>
{t("main_title")}
{t("main_subtitle")}
- )
- }
+ ),
+ [t],
+ );
- const tabBar = (props: MaterialTabBarProps) => (
- name}
- labelStyle={commonStyles.tabText}
- indicatorStyle={{ backgroundColor: colors.tab_focused }}
- />
- )
+ const tabBar = useCallback(
+ (props: MaterialTabBarProps) => (
+ name}
+ labelStyle={commonStyles.tabText}
+ indicatorStyle={{ backgroundColor: colors.tab_focused }}
+ />
+ ),
+ [],
+ );
const tabView = () => {
return (
@@ -106,27 +109,27 @@ export default function IndexScreen() {
headerContainerStyle={styles.tab}
renderHeader={header}
renderTabBar={tabBar}
- headerHeight={headerHeight}
- initialTabName={t('tab_pin')}
+ initialTabName={t("tab_pin")}
+ allowHeaderOverscroll
>
-
+
-
+
-
+
-
+
-
+
-
+
- )
- }
+ );
+ };
return (
@@ -138,7 +141,7 @@ export default function IndexScreen() {
onDismiss={hideSnackBar}
/>
- )
+ );
}
const styles = StyleSheet.create({
@@ -146,16 +149,16 @@ const styles = StyleSheet.create({
flex: 1,
},
header: {
- width: '100%',
- alignItems: 'center',
- justifyContent: 'center',
- position: 'absolute',
+ width: "100%",
+ alignItems: "center",
+ justifyContent: "center",
+ position: "absolute",
},
tab: {
elevation: 0,
backgroundColor: colors.background,
borderBottomWidth: 1,
- borderColor: colors.tab_underline
+ borderColor: colors.tab_underline,
},
indicator: { backgroundColor: colors.tab_focused },
-})
\ No newline at end of file
+});
diff --git a/components/BiometricsSwitch.tsx b/components/BiometricsSwitch.tsx
index acac8cb..2b6d0d8 100644
--- a/components/BiometricsSwitch.tsx
+++ b/components/BiometricsSwitch.tsx
@@ -16,25 +16,31 @@
* limitations under the License.
*/
-import { Image, StyleSheet, Switch, SwitchProps, Text, View } from "react-native"
-import { colors } from "../styles"
-import * as React from "react"
-import { t } from "../utils/i18n"
+import {
+ Image,
+ StyleSheet,
+ Switch,
+ SwitchProps,
+ Text,
+ View,
+} from "react-native";
+import { colors } from "../styles";
+import * as React from "react";
+import { t } from "../utils/i18n";
export const BiometricsSwitchButton = (props: BiometricsSwitchProps) => {
return (
-
-
+
+
-
- {t('biometrics_switch_title')}
-
-
- {t('biometrics_switch_desc')}
-
+ {t("biometrics_switch_title")}
+ {t("biometrics_switch_desc")}
-
+
{
value={props.value}
/>
- )
-}
+ );
+};
interface BiometricsSwitchProps extends SwitchProps {
accessibilityLabel: string;
@@ -55,8 +61,8 @@ interface BiometricsSwitchProps extends SwitchProps {
const styles = StyleSheet.create({
normalBg: {
marginTop: 16,
- flexDirection: 'row',
- justifyContent: 'space-between'
+ flexDirection: "row",
+ justifyContent: "space-between",
},
mainText: {
color: colors.social_login_text,
@@ -68,4 +74,4 @@ const styles = StyleSheet.create({
fontWeight: "400",
fontSize: 14,
},
-})
+});
diff --git a/components/CommonInputText.tsx b/components/CommonInputText.tsx
index f97f6eb..b69ae24 100644
--- a/components/CommonInputText.tsx
+++ b/components/CommonInputText.tsx
@@ -16,9 +16,9 @@
* limitations under the License.
*/
-import { TextInput, TextInputProps } from "react-native"
-import { colors, commonStyles } from "../styles"
-import React from "react"
+import { TextInput, TextInputProps } from "react-native";
+import { colors, commonStyles } from "../styles";
+import React from "react";
export default function CommonInputText(props: TextInputProps) {
return (
@@ -29,5 +29,5 @@ export default function CommonInputText(props: TextInputProps) {
placeholderTextColor={colors.placeholder}
style={[commonStyles.normalInputField, props.style]}
/>
- )
+ );
}
diff --git a/components/CopyableText.tsx b/components/CopyableText.tsx
index 28eae45..f87b7db 100644
--- a/components/CopyableText.tsx
+++ b/components/CopyableText.tsx
@@ -16,35 +16,43 @@
* limitations under the License.
*/
-import { Image, Text, TouchableOpacity } from "react-native"
-import { commonStyles } from "../styles"
-import React from "react"
-import * as Clipboard from 'expo-clipboard'
+import { Image, Text, TouchableOpacity } from "react-native";
+import { commonStyles } from "../styles";
+import React from "react";
+import * as Clipboard from "expo-clipboard";
export type CopyableTextProps = {
accessibilityLabel: string;
value: string | undefined | null;
};
-export default function CopyableText({ accessibilityLabel, value }: CopyableTextProps) {
+export default function CopyableText({
+ accessibilityLabel,
+ value,
+}: CopyableTextProps) {
return (
{
if (value) {
if (__DEV__) {
- console.log(value)
+ console.log(value);
}
- await Clipboard.setStringAsync(value)
+ await Clipboard.setStringAsync(value);
}
- }}>
+ }}
+ >
+ style={[commonStyles.normalValueText]}
+ >
{value}
-
+
- )
+ );
}
diff --git a/components/EmailTab.tsx b/components/EmailTab.tsx
index 911ab0e..877e163 100644
--- a/components/EmailTab.tsx
+++ b/components/EmailTab.tsx
@@ -16,87 +16,87 @@
* limitations under the License.
*/
-import * as React from "react"
-import { Text, View } from "react-native"
-import { MainButton } from "./MainButton"
-import { useTranslation } from 'react-i18next'
-import { commonStyles } from "../styles"
-import CommonInputText from "./CommonInputText"
-import useWalletSdk from "../utils/useWalletSdk"
-import { AuthMode } from "../redux/types"
-import { ShowSnackBarFn } from "../utils/useSnackBar"
-import CopyableText from "./CopyableText"
-import { WalletSdk } from "@circle-fin/w3s-pw-react-native-sdk"
-import RequiredMarkText from "./RequiredMarkText"
-import { GoExecuteButton } from "./GoExecuteButton"
-import { useRouter } from "expo-router"
+import * as React from "react";
+import { Text, View } from "react-native";
+import { MainButton } from "./MainButton";
+import { useTranslation } from "react-i18next";
+import { commonStyles } from "../styles";
+import CommonInputText from "./CommonInputText";
+import useWalletSdk from "../utils/useWalletSdk";
+import { AuthMode } from "../redux/types";
+import { ShowSnackBarFn } from "../utils/useSnackBar";
+import CopyableText from "./CopyableText";
+import { WalletSdk } from "@circle-fin/w3s-pw-react-native-sdk";
+import RequiredMarkText from "./RequiredMarkText";
+import { GoExecuteButton } from "./GoExecuteButton";
+import { useRouter } from "expo-router";
interface EmailTabProps {
showSnackBar: ShowSnackBarFn;
}
export const EmailTab: React.FC = ({ showSnackBar }) => {
- const router = useRouter()
- const { t } = useTranslation()
-
+ const router = useRouter();
+ const { t } = useTranslation();
+
const {
- appId,
- dispatchAppId,
- verifyOtp,
+ appId,
+ dispatchAppId,
+ verifyOtp,
dispatchLoginResult,
- // Get email auth data directly from the hook
+ // Get email auth data directly from the hook
emailUserToken,
- emailEncryptionKey
- } = useWalletSdk(showSnackBar)
-
- const [deviceToken, setDeviceToken] = React.useState("")
- const [deviceEncryptionKey, setDeviceEncryptionKey] = React.useState("")
- const [otpToken, setOtpToken] = React.useState("")
+ emailEncryptionKey,
+ } = useWalletSdk(showSnackBar);
+
+ const [deviceToken, setDeviceToken] = React.useState("");
+ const [deviceEncryptionKey, setDeviceEncryptionKey] = React.useState("");
+ const [otpToken, setOtpToken] = React.useState("");
const isEmailLoginDisabled = () => {
- return (
- !appId ||
- !deviceToken ||
- !deviceEncryptionKey ||
- !otpToken
- )
- }
+ return !appId || !deviceToken || !deviceEncryptionKey || !otpToken;
+ };
return (
- {t("device_id_title")}
-
-
-
+
+ {t("device_id_title")}
+
+
+
+
{
- dispatchAppId(value)
+ dispatchAppId(value);
}}
value={appId}
/>
-
-
+
+
-
-
+
+
-
-
+
+
-
+
= ({ showSnackBar }) => {
text={t("email_login_bt")}
onPress={() => {
verifyOtp(
- otpToken,
- deviceToken,
+ otpToken,
+ deviceToken,
deviceEncryptionKey,
- loginResult => {
- dispatchLoginResult(AuthMode.email, loginResult)
- showSnackBar(t('login_success'), true)
+ (loginResult) => {
+ dispatchLoginResult(AuthMode.email, loginResult);
+ showSnackBar(t("login_success"), true);
},
- e => {
- showSnackBar(e.message, false)
- }
- )
+ (e) => {
+ showSnackBar(e?.message || "Unknown error", false);
+ },
+ );
}}
/>
-
+
{emailUserToken != null && emailEncryptionKey != null && (
{
router.push({
- pathname: '/ExecuteScreen',
- params: {
+ pathname: "/ExecuteScreen",
+ params: {
authMode: AuthMode.email,
userToken: emailUserToken,
- encryptionKey: emailEncryptionKey
- }
- })
+ encryptionKey: emailEncryptionKey,
+ },
+ });
}}
/>
)}
- )
-}
\ No newline at end of file
+ );
+};
diff --git a/components/GoExecuteButton.tsx b/components/GoExecuteButton.tsx
index dbddc7e..2d693c7 100644
--- a/components/GoExecuteButton.tsx
+++ b/components/GoExecuteButton.tsx
@@ -16,35 +16,39 @@
* limitations under the License.
*/
-import { Image, StyleSheet, Text, TouchableOpacity, TouchableOpacityProps, View } from "react-native"
-import { colors } from "../styles"
-import * as React from "react"
-import { useTranslation } from 'react-i18next'
+import {
+ Image,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ TouchableOpacityProps,
+ View,
+} from "react-native";
+import { colors } from "../styles";
+import * as React from "react";
+import { useTranslation } from "react-i18next";
export const GoExecuteButton = (props: GoExecuteButtonProps) => {
- const { t } = useTranslation()
+ const { t } = useTranslation();
return (
-
+
-
+
-
- {t('go_execute_bt')}
-
-
- {t('go_execute_bt_desc')}
-
+ {t("go_execute_bt")}
+ {t("go_execute_bt_desc")}
- )
-}
+ );
+};
interface GoExecuteButtonProps extends TouchableOpacityProps {
accessibilityLabel: string;
@@ -58,7 +62,7 @@ const styles = StyleSheet.create({
borderRadius: 16,
borderColor: colors.input_boarder,
marginTop: 16,
- flexDirection: 'row',
+ flexDirection: "row",
},
mainText: {
color: colors.tab_focused,
@@ -70,4 +74,4 @@ const styles = StyleSheet.create({
fontWeight: "400",
fontSize: 14,
},
-})
+});
diff --git a/components/HyperlinkText.tsx b/components/HyperlinkText.tsx
index 89cdf9c..87857c0 100644
--- a/components/HyperlinkText.tsx
+++ b/components/HyperlinkText.tsx
@@ -16,9 +16,9 @@
* limitations under the License.
*/
-import { Linking, StyleSheet, Text } from "react-native"
-import { colors } from "../styles"
-import React from "react"
+import { Linking, StyleSheet, Text } from "react-native";
+import { colors } from "../styles";
+import React from "react";
export type HyperlinkTextProps = {
fullText: string;
@@ -26,22 +26,29 @@ export type HyperlinkTextProps = {
url: string;
};
-export default function HyperlinkText({ fullText, linkText, url }: HyperlinkTextProps) {
- const startIndex = linkText ? fullText.indexOf(linkText) : -1
-
+export default function HyperlinkText({
+ fullText,
+ linkText,
+ url,
+}: HyperlinkTextProps) {
+ const startIndex = linkText ? fullText.indexOf(linkText) : -1;
+
const getPlainArr = () => {
switch (startIndex) {
case 0:
- return ['', fullText.substring(linkText.length)]
+ return ["", fullText.substring(linkText.length)];
case -1:
- return [fullText, '']
+ return [fullText, ""];
default:
- return [fullText.substring(0, startIndex), fullText.substring(startIndex + linkText.length)]
+ return [
+ fullText.substring(0, startIndex),
+ fullText.substring(startIndex + linkText.length),
+ ];
}
- }
-
- const plainArr = getPlainArr()
-
+ };
+
+ const plainArr = getPlainArr();
+
return (
{plainArr[0]}
@@ -49,14 +56,15 @@ export default function HyperlinkText({ fullText, linkText, url }: HyperlinkText
{
- Linking.openURL(url)
- }}>
+ Linking.openURL(url);
+ }}
+ >
{linkText}
)}
{plainArr[1]}
- )
+ );
}
const styles = StyleSheet.create({
@@ -71,4 +79,4 @@ const styles = StyleSheet.create({
fontWeight: "600",
fontSize: 14,
},
-})
+});
diff --git a/components/MainButton.tsx b/components/MainButton.tsx
index 840238d..8478d37 100644
--- a/components/MainButton.tsx
+++ b/components/MainButton.tsx
@@ -16,43 +16,36 @@
* limitations under the License.
*/
-import type { TouchableOpacityProps } from "react-native"
-import { Text, TouchableOpacity } from "react-native"
-import { commonStyles } from "../styles"
-import * as React from "react"
+import type { TouchableOpacityProps } from "react-native";
+import { Text, TouchableOpacity } from "react-native";
+import { commonStyles } from "../styles";
+import * as React from "react";
export const MainButton = (props: MainButtonProps) => {
- let normalBg = commonStyles.mainButton
- let disabledBg = commonStyles.disabledMainButton
- let normalText = commonStyles.mainButtonText
- let disabledText = commonStyles.disabledMainButtonText
-
+ let normalBg = commonStyles.mainButton;
+ let disabledBg = commonStyles.disabledMainButton;
+ let normalText = commonStyles.mainButtonText;
+ let disabledText = commonStyles.disabledMainButtonText;
+
if (props.isSecondary) {
- normalBg = commonStyles.secondaryButton
- disabledBg = commonStyles.disabledSecondaryButton
- normalText = commonStyles.secondaryButtonText
- disabledText = commonStyles.disabledSecondaryButtonText
+ normalBg = commonStyles.secondaryButton;
+ disabledBg = commonStyles.disabledSecondaryButton;
+ normalText = commonStyles.secondaryButtonText;
+ disabledText = commonStyles.disabledSecondaryButtonText;
}
-
+
return (
-
+ style={[normalBg, props.disabled && disabledBg, props.style]}
+ >
+
{props.text}
- )
-}
+ );
+};
interface MainButtonProps extends TouchableOpacityProps {
disabled: boolean;
diff --git a/components/PinTab.tsx b/components/PinTab.tsx
index d4bf540..2299279 100644
--- a/components/PinTab.tsx
+++ b/components/PinTab.tsx
@@ -16,32 +16,37 @@
* limitations under the License.
*/
-import * as React from "react"
-import { Text, View } from "react-native"
-import { MainButton } from "./MainButton"
-import { useTranslation } from 'react-i18next'
-import { commonStyles } from "../styles"
-import CommonInputText from "./CommonInputText"
-import useWalletSdk from "../utils/useWalletSdk"
-import { ShowSnackBarFn } from "../utils/useSnackBar"
-import RequiredMarkText from "./RequiredMarkText"
-import { BiometricsSwitchButton } from "./BiometricsSwitch"
+import * as React from "react";
+import { Text, View } from "react-native";
+import { MainButton } from "./MainButton";
+import { useTranslation } from "react-i18next";
+import { commonStyles } from "../styles";
+import CommonInputText from "./CommonInputText";
+import useWalletSdk from "../utils/useWalletSdk";
+import { ShowSnackBarFn } from "../utils/useSnackBar";
+import RequiredMarkText from "./RequiredMarkText";
+import { BiometricsSwitchButton } from "./BiometricsSwitch";
interface PinTabProps {
showSnackBar: ShowSnackBarFn;
}
export const PinTab: React.FC = ({ showSnackBar }) => {
- const { t } = useTranslation()
+ const { t } = useTranslation();
const {
- endpoint, appId, enableBiometricsPin,
- dispatchEndpoint, dispatchAppId, dispatchEnableBiometrics,
- execute, setBiometricsPin
- } = useWalletSdk(showSnackBar)
- const [userToken, setUserToken] = React.useState("")
- const [encryptionKey, setEncryptionKey] = React.useState("")
- const [challengeId, setChallengeId] = React.useState("")
-
+ endpoint,
+ appId,
+ enableBiometricsPin,
+ dispatchEndpoint,
+ dispatchAppId,
+ dispatchEnableBiometrics,
+ execute,
+ setBiometricsPin,
+ } = useWalletSdk(showSnackBar);
+ const [userToken, setUserToken] = React.useState("");
+ const [encryptionKey, setEncryptionKey] = React.useState("");
+ const [challengeId, setChallengeId] = React.useState("");
+
const isSetBiometricsPinDisabled = () => {
return (
!enableBiometricsPin ||
@@ -49,54 +54,48 @@ export const PinTab: React.FC = ({ showSnackBar }) => {
!appId ||
!encryptionKey ||
!userToken
- )
- }
-
+ );
+ };
+
const isExecuteDisabled = () => {
- return (
- !endpoint ||
- !appId ||
- !userToken ||
- !encryptionKey ||
- !challengeId
- )
- }
-
+ return !endpoint || !appId || !userToken || !encryptionKey || !challengeId;
+ };
+
const successCallback = (result: any) => {
- showSnackBar(t('execute_success'), true)
- console.log(JSON.stringify(result))
- }
-
- const errorCallback = (e: any) => {
- const message = e?.message || 'Unknown error'
- showSnackBar(message, false)
- }
-
+ showSnackBar(t("execute_success"), true);
+ console.log(JSON.stringify(result));
+ };
+
+ const errorCallback = (e: any) => {
+ const message = e?.message || "Unknown error";
+ showSnackBar(message, false);
+ };
+
return (
-
+
{
- dispatchEndpoint(value)
+ dispatchEndpoint(value);
}}
value={endpoint}
/>
-
+
{
- dispatchAppId(value)
+ dispatchAppId(value);
}}
value={appId}
/>
-
+
-
+
= ({ showSnackBar }) => {
accessibilityLabel={"biometricsSwitch"}
enableSwitch={enableBiometricsPin}
onValueChange={(value) => {
- dispatchEnableBiometrics(value)
+ dispatchEnableBiometrics(value);
}}
value={enableBiometricsPin}
/>
@@ -122,7 +121,13 @@ export const PinTab: React.FC = ({ showSnackBar }) => {
isSecondary={false}
text={t("execute_bt")}
onPress={() => {
- execute(userToken, encryptionKey, challengeId, successCallback, errorCallback)
+ execute(
+ userToken,
+ encryptionKey,
+ challengeId,
+ successCallback,
+ errorCallback,
+ );
}}
/>
= ({ showSnackBar }) => {
disabled={isSetBiometricsPinDisabled()}
text={t("set_biometrics_pin_bt")}
onPress={() => {
- setBiometricsPin(userToken, encryptionKey, successCallback, errorCallback)
+ setBiometricsPin(
+ userToken,
+ encryptionKey,
+ successCallback,
+ errorCallback,
+ );
}}
/>
- )
-}
\ No newline at end of file
+ );
+};
diff --git a/components/RequiredMarkText.tsx b/components/RequiredMarkText.tsx
index 331d263..337cf05 100644
--- a/components/RequiredMarkText.tsx
+++ b/components/RequiredMarkText.tsx
@@ -16,35 +16,35 @@
* limitations under the License.
*/
-import { Text, View, StyleProp, TextStyle } from "react-native"
-import { commonStyles } from "../styles"
-import React from "react"
-import { useTranslation } from 'react-i18next'
+import { Text, View, StyleProp, TextStyle, ViewStyle } from "react-native";
+import { commonStyles } from "../styles";
+import React from "react";
+import { useTranslation } from "react-i18next";
export type RequiredMarkTextProps = {
- text: string,
- style?: StyleProp | undefined
- markStyle?: StyleProp | undefined
-}
+ text: string;
+ style?: StyleProp | undefined;
+ markStyle?: StyleProp | undefined;
+};
export default function RequiredMarkText(props: RequiredMarkTextProps) {
- const { t } = useTranslation()
+ const { t } = useTranslation();
return (
-
-
- {props.text}
-
+
+ {props.text}
- {t('required_mark')}
+ {t("required_mark")}
- )
+ );
}
diff --git a/components/SnackBar.tsx b/components/SnackBar.tsx
index 7275cda..cc389b0 100644
--- a/components/SnackBar.tsx
+++ b/components/SnackBar.tsx
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-import React, { useEffect, useRef } from 'react'
-import { Animated, StyleSheet, Text } from 'react-native'
-import { colors } from '../styles'
-import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import React, { useEffect, useRef } from "react";
+import { Animated, StyleSheet, Text } from "react-native";
+import { colors } from "../styles";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
interface SnackBarProps {
visible: boolean;
@@ -36,8 +36,8 @@ export const SnackBar: React.FC = ({
duration = 3000,
onDismiss,
}) => {
- const opacity = useRef(new Animated.Value(0)).current
- const insets = useSafeAreaInsets()
+ const opacity = useRef(new Animated.Value(0)).current;
+ const insets = useSafeAreaInsets();
useEffect(() => {
if (visible) {
@@ -52,33 +52,33 @@ export const SnackBar: React.FC = ({
toValue: 0,
duration: 300,
useNativeDriver: true,
- })
+ }),
]).start(() => {
if (onDismiss) {
- onDismiss()
+ onDismiss();
}
- })
+ });
}
- }, [visible, duration, opacity, onDismiss])
+ }, [visible, duration, opacity, onDismiss]);
- if (!visible) return null
+ if (!visible) return null;
return (
-
- = ({
{message}
- )
-}
+ );
+};
const styles = StyleSheet.create({
container: {
- position: 'absolute',
+ position: "absolute",
left: 20,
right: 20,
padding: 10,
borderRadius: 5,
- alignItems: 'center',
- justifyContent: 'center',
+ alignItems: "center",
+ justifyContent: "center",
zIndex: 1000,
},
successContainer: {
@@ -111,9 +111,9 @@ const styles = StyleSheet.create({
fontSize: 16,
},
successMessage: {
- color: 'white',
+ color: "white",
},
errorMessage: {
color: colors.snackbar_error_text,
},
-})
\ No newline at end of file
+});
diff --git a/components/SocialLoginButton.tsx b/components/SocialLoginButton.tsx
index 70a26b7..1999973 100644
--- a/components/SocialLoginButton.tsx
+++ b/components/SocialLoginButton.tsx
@@ -16,40 +16,50 @@
* limitations under the License.
*/
-import { Image, StyleSheet, Text, TouchableOpacity, TouchableOpacityProps } from "react-native"
-import { colors } from "../styles"
-import * as React from "react"
-import { useTranslation } from 'react-i18next'
-import { SocialProvider } from "@circle-fin/w3s-pw-react-native-sdk"
+import {
+ Image,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ TouchableOpacityProps,
+} from "react-native";
+import { colors } from "../styles";
+import * as React from "react";
+import { useTranslation } from "react-i18next";
+import { SocialProvider } from "@circle-fin/w3s-pw-react-native-sdk";
export const SocialLoginButton = (props: SocialLoginButtonProps) => {
- const { t } = useTranslation()
- const name = props.provider.toLowerCase()
-
- let icon = require("../assets/image/ic_google.png")
+ const { t } = useTranslation();
+ const name = props.provider.toLowerCase();
+
+ let icon = require("../assets/image/ic_google.png");
switch (props.provider) {
case SocialProvider.Facebook:
- icon = require("../assets/image/ic_facebook.png")
- break
+ icon = require("../assets/image/ic_facebook.png");
+ break;
case SocialProvider.Apple:
- icon = require("../assets/image/ic_apple.png")
- break
+ icon = require("../assets/image/ic_apple.png");
+ break;
}
-
+
return (
+ style={[
+ props.disabled ? styles.disabledBg : styles.normalBg,
+ props.style,
+ ]}
+ >
{t(`${name}_bt`)}
- )
-}
+ );
+};
interface SocialLoginButtonProps extends TouchableOpacityProps {
disabled: boolean;
@@ -64,18 +74,18 @@ const styles = StyleSheet.create({
borderRadius: 6,
borderColor: colors.social_login_bt_boarder,
marginTop: 12,
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center'
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
},
disabledBg: {
backgroundColor: colors.social_login_bt_disabled,
minHeight: 40,
borderRadius: 6,
marginTop: 12,
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center'
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
},
normalText: {
color: colors.social_login_text,
@@ -87,4 +97,4 @@ const styles = StyleSheet.create({
fontWeight: "500",
fontSize: 16,
},
-})
+});
diff --git a/components/SocialTab.tsx b/components/SocialTab.tsx
index 59615d5..b279901 100644
--- a/components/SocialTab.tsx
+++ b/components/SocialTab.tsx
@@ -16,105 +16,115 @@
* limitations under the License.
*/
-import * as React from "react"
-import { Text, View } from "react-native"
-import { useTranslation } from 'react-i18next'
-import { commonStyles } from "../styles"
-import CommonInputText from "./CommonInputText"
-import CopyableText from "./CopyableText"
-import { WalletSdk, SocialProvider } from "@circle-fin/w3s-pw-react-native-sdk"
-import useWalletSdk from "../utils/useWalletSdk"
-import { AuthMode } from "../redux/types"
-import { ShowSnackBarFn } from "../utils/useSnackBar"
-import RequiredMarkText from "./RequiredMarkText"
-import { SocialLoginButton } from "./SocialLoginButton"
-import HyperlinkText from "./HyperlinkText"
-import { GoExecuteButton } from "./GoExecuteButton"
-import { useRouter } from "expo-router"
-import { useAppDispatch, useAppSelector } from "@redux/hooks"
-import { setAppId } from "@features/settings/settingsSlice"
-import { selectSocialUserToken, selectSocialEncryptionKey } from "../features/result/resultSlice"
+import * as React from "react";
+import { Text, View } from "react-native";
+import { useTranslation } from "react-i18next";
+import { commonStyles } from "../styles";
+import CommonInputText from "./CommonInputText";
+import CopyableText from "./CopyableText";
+import { WalletSdk, SocialProvider } from "@circle-fin/w3s-pw-react-native-sdk";
+import useWalletSdk from "../utils/useWalletSdk";
+import { AuthMode } from "../redux/types";
+import { ShowSnackBarFn } from "../utils/useSnackBar";
+import RequiredMarkText from "./RequiredMarkText";
+import { SocialLoginButton } from "./SocialLoginButton";
+import HyperlinkText from "./HyperlinkText";
+import { GoExecuteButton } from "./GoExecuteButton";
+import { useRouter } from "expo-router";
+import { useAppSelector } from "@redux/hooks";
+import {
+ selectSocialUserToken,
+ selectSocialEncryptionKey,
+} from "../features/result/resultSlice";
interface SocialTabProps {
showSnackBar: ShowSnackBarFn;
}
export const SocialTab: React.FC = ({ showSnackBar }) => {
- const DOC_URL = 'https://developers.circle.com/w3s/docs/authentication-methods#create-a-wallet-with-social-logins'
- const router = useRouter()
- const { t } = useTranslation()
- const dispatch = useAppDispatch()
- const { appId: reduxAppId } = useAppSelector(state => state.settings)
- const socialUserToken = useAppSelector(selectSocialUserToken)
- const socialEncryptionKey = useAppSelector(selectSocialEncryptionKey)
-
- const {
- appId,
- dispatchAppId,
- logoutAndLogin,
- dispatchLoginResult
- } = useWalletSdk(showSnackBar)
-
- const [deviceToken, setDeviceToken] = React.useState("")
- const [deviceEncryptionKey, setDeviceEncryptionKey] = React.useState("")
+ const DOC_URL =
+ "https://developers.circle.com/w3s/docs/authentication-methods#create-a-wallet-with-social-logins";
+ const router = useRouter();
+ const { t } = useTranslation();
+ const { appId: reduxAppId } = useAppSelector((state) => state.settings);
+ const socialUserToken = useAppSelector(selectSocialUserToken);
+ const socialEncryptionKey = useAppSelector(selectSocialEncryptionKey);
+
+ const { appId, dispatchAppId, logoutAndLogin, dispatchLoginResult } =
+ useWalletSdk(showSnackBar);
+
+ const [deviceToken, setDeviceToken] = React.useState("");
+ const [deviceEncryptionKey, setDeviceEncryptionKey] = React.useState("");
const LoginButton = (provider: SocialProvider) => {
return (
- {
logoutAndLogin(
- provider,
- deviceToken,
+ provider,
+ deviceToken,
deviceEncryptionKey,
- loginResult => {
- dispatchLoginResult(AuthMode.social, loginResult)
- showSnackBar(t('login_success'), true)
- console.log('login_success')
+ (loginResult) => {
+ dispatchLoginResult(AuthMode.social, loginResult);
+ showSnackBar(t("login_success"), true);
+ console.log("login_success");
+ },
+ (e) => {
+ console.log("login_failed:" + (e?.message || "Unknown error"));
+ showSnackBar(e?.message || "Unknown error", false);
},
- e => {
- console.log('login_failed:'+e.message)
- showSnackBar(e.message, false)
- }
- )
+ );
}}
/>
- )
- }
+ );
+ };
const SectionText = () => {
return (
-
+
{t("log_in_with_section")}
- )
- }
+ );
+ };
return (
- {t("device_id_title")}
-
-
-
+
+ {t("device_id_title")}
+
+
+
+
{
- dispatchAppId(value)
+ dispatchAppId(value);
}}
value={appId || reduxAppId}
/>
-
-
+
+
-
-
+
+
= ({ showSnackBar }) => {
{LoginButton(SocialProvider.Google)}
{LoginButton(SocialProvider.Facebook)}
{LoginButton(SocialProvider.Apple)}
-
+
{socialUserToken != null && socialEncryptionKey != null && (
{
router.push({
- pathname: '/ExecuteScreen',
- params: {
+ pathname: "/ExecuteScreen",
+ params: {
authMode: AuthMode.social,
userToken: socialUserToken,
- encryptionKey: socialEncryptionKey
- }
- })
+ encryptionKey: socialEncryptionKey,
+ },
+ });
}}
/>
)}
-
-
- )
-}
\ No newline at end of file
+ );
+};
diff --git a/customize/DefaultCustomizer.ts b/customize/DefaultCustomizer.ts
index a89a344..4fd85fb 100644
--- a/customize/DefaultCustomizer.ts
+++ b/customize/DefaultCustomizer.ts
@@ -28,263 +28,251 @@ import {
TextKey,
TextsKey,
WalletSdk,
-} from '@circle-fin/w3s-pw-react-native-sdk'
+} from "@circle-fin/w3s-pw-react-native-sdk";
-import { colors } from '../styles'
+import { colors } from "../styles";
export const DefaultCustomizer = {
setup() {
- _setSecurityQuestions()
- _setDismissOnCallbackMap()
- _setTextConfigsMap()
- _setIconTextConfigsMap()
- _setTextConfigMap()
- _setErrorStringMap()
- _setImageMap()
- _setDateFormat()
- _setDebugging()
- _setCustomUserAgent()
- }
-}
+ _setSecurityQuestions();
+ _setDismissOnCallbackMap();
+ _setTextConfigsMap();
+ _setIconTextConfigsMap();
+ _setTextConfigMap();
+ _setErrorStringMap();
+ _setImageMap();
+ _setDateFormat();
+ _setDebugging();
+ _setCustomUserAgent();
+ },
+};
const _setSecurityQuestions = () => {
WalletSdk.setSecurityQuestions([
- new SecurityQuestion('What was your childhood nickname?', InputType.text),
- new SecurityQuestion('What is your fatherโs middle name?', InputType.text),
- new SecurityQuestion('When is your birthday?', InputType.datePicker),
+ new SecurityQuestion("What was your childhood nickname?", InputType.text),
+ new SecurityQuestion("What is your fatherโs middle name?", InputType.text),
+ new SecurityQuestion("When is your birthday?", InputType.datePicker),
new SecurityQuestion(
"When is your father's birthday?",
InputType.datePicker,
),
- new SecurityQuestion('When is your favorite date?', InputType.datePicker),
- new SecurityQuestion('What is the name of your first pet?'),
- new SecurityQuestion('What is the name of the first street you lived on?'),
- new SecurityQuestion('What is your favorite song?'),
- new SecurityQuestion('What is your favorite color?'),
- new SecurityQuestion('What is your favorite country?')
- ])
-}
+ new SecurityQuestion("When is your favorite date?", InputType.datePicker),
+ new SecurityQuestion("What is the name of your first pet?"),
+ new SecurityQuestion("What is the name of the first street you lived on?"),
+ new SecurityQuestion("What is your favorite song?"),
+ new SecurityQuestion("What is your favorite color?"),
+ new SecurityQuestion("What is your favorite country?"),
+ ]);
+};
const _setDismissOnCallbackMap = () => {
- const map = new Map()
- map.set(ErrorCode.unknown, true)
- map.set(ErrorCode.userCanceled, true)
- map.set(ErrorCode.networkError, true)
- map.set(ErrorCode.biometricsKeyPermanentlyInvalidated, true)
- map.set(ErrorCode.biometricsUserSkip, true)
- map.set(ErrorCode.biometricsUserDisableForPin, true)
- map.set(ErrorCode.biometricsUserLockout, true)
- map.set(ErrorCode.biometricsUserLockoutPermanent, true)
- map.set(ErrorCode.biometricsUserNotAllowPermission, true)
- map.set(ErrorCode.biometricsInternalError, true)
- WalletSdk.setDismissOnCallbackMap(map)
-}
+ const map = new Map();
+ map.set(ErrorCode.unknown, true);
+ map.set(ErrorCode.userCanceled, true);
+ map.set(ErrorCode.networkError, true);
+ map.set(ErrorCode.biometricsKeyPermanentlyInvalidated, true);
+ map.set(ErrorCode.biometricsUserSkip, true);
+ map.set(ErrorCode.biometricsUserDisableForPin, true);
+ map.set(ErrorCode.biometricsUserLockout, true);
+ map.set(ErrorCode.biometricsUserLockoutPermanent, true);
+ map.set(ErrorCode.biometricsUserNotAllowPermission, true);
+ map.set(ErrorCode.biometricsInternalError, true);
+ WalletSdk.setDismissOnCallbackMap(map);
+};
const _setTextConfigsMap = () => {
- const map = new Map()
+ const map = new Map();
map.set(TextsKey.securityQuestionHeaders, [
new TextConfig("Choose your 1st question"),
- new TextConfig("Choose your 2nd question")
- ])
+ new TextConfig("Choose your 2nd question"),
+ ]);
map.set(TextsKey.securitySummaryQuestionHeaders, [
new TextConfig("1st Question"),
- new TextConfig("2nd Question")
- ])
+ new TextConfig("2nd Question"),
+ ]);
map.set(TextsKey.enterPinCodeHeadline, [
new TextConfig("ENTER your "),
- new TextConfig("PIN", colors.primary)
- ])
+ new TextConfig("PIN", colors.primary),
+ ]);
map.set(TextsKey.securityIntroHeadline, [
new TextConfig("Set up your "),
- new TextConfig("Recovery Method", colors.primary)
- ])
+ new TextConfig("Recovery Method", colors.primary),
+ ]);
map.set(TextsKey.newPinCodeHeadline, [
new TextConfig("ENTER your "),
- new TextConfig("PIN", colors.primary)
- ])
+ new TextConfig("PIN", colors.primary),
+ ]);
map.set(TextsKey.securityIntroLink, [
new TextConfig("Learn more"),
- new TextConfig("https://path/terms-policies/privacy-notice/")
- ])
+ new TextConfig("https://path/terms-policies/privacy-notice/"),
+ ]);
map.set(TextsKey.recoverPinCodeHeadline, [
new TextConfig("Recover your "),
- new TextConfig("PIN", colors.primary)
- ])
- WalletSdk.setTextConfigsMap(map)
-}
+ new TextConfig("PIN", colors.primary),
+ ]);
+ WalletSdk.setTextConfigsMap(map);
+};
const _setIconTextConfigsMap = () => {
- const map = new Map()
+ const map = new Map();
map.set(IconTextsKey.securityConfirmationItems, [
new IconTextConfig(
- require("../assets/image/ic_intro_item0_icon.png"),
- new TextConfig("This is the only way to recover my account access. ")
+ require("../assets/image/ic_intro_item0_icon.png"),
+ new TextConfig("This is the only way to recover my account access. "),
),
new IconTextConfig(
- require("../assets/image/ic_intro_item1_icon.png"),
- new TextConfig(
- "Circle wonโt store my answers so itโs my responsibility to remember them."
- )
+ require("../assets/image/ic_intro_item1_icon.png"),
+ new TextConfig(
+ "Circle wonโt store my answers so itโs my responsibility to remember them.",
+ ),
),
new IconTextConfig(
- require("../assets/image/ic_intro_item2_icon.png"),
- new TextConfig(
- "I will lose access to my wallet and my digital assets if I forget my answers. "
- )
- )
- ])
- WalletSdk.setIconTextConfigsMap(map)
-}
-const _setTextConfigMap = () => {
- const map = new Map()
- const font = 'Inter-Semi-Bold'
- const onlyFontConfig = new TextConfig(undefined, undefined, font)
- map.set(
- TextKey.circlepw_recover_pincode_answer_input_placeholder as TextKey,
+ require("../assets/image/ic_intro_item2_icon.png"),
new TextConfig(
- "Type your answer here",
- colors.placeholder,
- 'Inter-Regular',
+ "I will lose access to my wallet and my digital assets if I forget my answers. ",
),
- )
+ ),
+ ]);
+ WalletSdk.setIconTextConfigsMap(map);
+};
+const _setTextConfigMap = () => {
+ const map = new Map();
+ const font = "Inter-Semi-Bold";
+ const onlyFontConfig = new TextConfig(undefined, undefined, font);
map.set(
- TextKey.circlepw_transaction_request_main_currency as TextKey,
- new TextConfig(
- 'USDC',
- undefined,
- font,
- ),
- )
+ TextKey.circlepw_recover_pincode_answer_input_placeholder as TextKey,
+ new TextConfig(
+ "Type your answer here",
+ colors.placeholder,
+ "Inter-Regular",
+ ),
+ );
map.set(
- TextKey.circlepw_transaction_request_exchange_value as TextKey,
- new TextConfig(
- 'โ$20 USD',
- undefined,
- font,
- ),
- )
+ TextKey.circlepw_transaction_request_main_currency as TextKey,
+ new TextConfig("USDC", undefined, font),
+ );
map.set(
- TextKey.circlepw_transaction_request_from as TextKey,
- new TextConfig(
- '0x9988770123456789ccii',
- undefined,
- font,
- ),
- )
+ TextKey.circlepw_transaction_request_exchange_value as TextKey,
+ new TextConfig("โ$20 USD", undefined, font),
+ );
+ map.set(
+ TextKey.circlepw_transaction_request_from as TextKey,
+ new TextConfig("0x9988770123456789ccii", undefined, font),
+ );
map.set(
- TextKey.circlepw_transaction_request_to_config as TextKey,
- onlyFontConfig,
- )
+ TextKey.circlepw_transaction_request_to_config as TextKey,
+ onlyFontConfig,
+ );
map.set(
- TextKey.circlepw_transaction_request_to_contract_name as TextKey,
- new TextConfig('uniswap.org', undefined, font),
- )
+ TextKey.circlepw_transaction_request_to_contract_name as TextKey,
+ new TextConfig("uniswap.org", undefined, font),
+ );
map.set(
- TextKey.circlepw_transaction_request_to_contract_url as TextKey,
- new TextConfig('https://uniswap.org', undefined, font),
- )
+ TextKey.circlepw_transaction_request_to_contract_url as TextKey,
+ new TextConfig("https://uniswap.org", undefined, font),
+ );
map.set(
- TextKey.circlepw_transaction_request_network_fee as TextKey,
- new TextConfig('0.1234 ETH', undefined, font),
- )
+ TextKey.circlepw_transaction_request_network_fee as TextKey,
+ new TextConfig("0.1234 ETH", undefined, font),
+ );
map.set(
- TextKey.circlepw_transaction_request_exchange_network_fee as TextKey,
- new TextConfig('โ$1.1 USD'),
- )
+ TextKey.circlepw_transaction_request_exchange_network_fee as TextKey,
+ new TextConfig("โ$1.1 USD"),
+ );
map.set(
- TextKey.circlepw_transaction_request_total_config as TextKey,
- onlyFontConfig,
- )
+ TextKey.circlepw_transaction_request_total_config as TextKey,
+ onlyFontConfig,
+ );
map.set(
- TextKey.circlepw_contract_interaction_abi_function_config as TextKey,
- onlyFontConfig,
- )
+ TextKey.circlepw_contract_interaction_abi_function_config as TextKey,
+ onlyFontConfig,
+ );
map.set(
- TextKey.circlepw_contract_interaction_data_details as TextKey,
- onlyFontConfig,
- )
+ TextKey.circlepw_contract_interaction_data_details as TextKey,
+ onlyFontConfig,
+ );
map.set(
- TextKey.circlepw_transaction_request_exchange_total_value as TextKey,
- new TextConfig('โ$21.1 USD'),
- )
+ TextKey.circlepw_transaction_request_exchange_total_value as TextKey,
+ new TextConfig("โ$21.1 USD"),
+ );
map.set(
- TextKey.circlepw_signature_request_contract_name as TextKey,
- new TextConfig('koalla.org', undefined, font),
- )
+ TextKey.circlepw_signature_request_contract_name as TextKey,
+ new TextConfig("koalla.org", undefined, font),
+ );
map.set(
- TextKey.circlepw_signature_request_contract_url as TextKey,
- new TextConfig('https://koalla.org', undefined, font),
- )
- WalletSdk.setTextConfigMap(map)
-}
+ TextKey.circlepw_signature_request_contract_url as TextKey,
+ new TextConfig("https://koalla.org", undefined, font),
+ );
+ WalletSdk.setTextConfigMap(map);
+};
const _setErrorStringMap = () => {
- const map = new Map()
- map.set(ErrorCode.incorrectUserPin, "The PIN you entered is incorrect.")
+ const map = new Map();
+ map.set(ErrorCode.incorrectUserPin, "The PIN you entered is incorrect.");
map.set(
- ErrorCode.insecurePinCode,
- "Your PIN canโt have repeating or consecutive numbers."
- )
- WalletSdk.setErrorStringMap(map)
-}
+ ErrorCode.insecurePinCode,
+ "Your PIN canโt have repeating or consecutive numbers.",
+ );
+ WalletSdk.setErrorStringMap(map);
+};
const _setImageMap = () => {
- const imageMap = new Map()
- imageMap.set(ImageKey.naviBack, require("../assets/image/ic_back.png"))
- imageMap.set(ImageKey.naviClose, require("../assets/image/ic_close.png"))
- imageMap.set(ImageKey.showPin, require("../assets/image/ic_show_pin.png"))
- imageMap.set(ImageKey.hidePin, require("../assets/image/ic_hide_pin.png"))
+ const imageMap = new Map();
+ imageMap.set(ImageKey.naviBack, require("../assets/image/ic_back.png"));
+ imageMap.set(ImageKey.naviClose, require("../assets/image/ic_close.png"));
+ imageMap.set(ImageKey.showPin, require("../assets/image/ic_show_pin.png"));
+ imageMap.set(ImageKey.hidePin, require("../assets/image/ic_hide_pin.png"));
imageMap.set(
- ImageKey.alertWindowIcon,
- require("../assets/image/ic_alert_window_icon.png")
- )
+ ImageKey.alertWindowIcon,
+ require("../assets/image/ic_alert_window_icon.png"),
+ );
imageMap.set(
- ImageKey.securityIntroMain,
- require("../assets/image/ic_intro_main_icon.png")
- )
+ ImageKey.securityIntroMain,
+ require("../assets/image/ic_intro_main_icon.png"),
+ );
imageMap.set(
- ImageKey.selectCheckMark,
- require("../assets/image/ic_select_checkmark.png")
- )
+ ImageKey.selectCheckMark,
+ require("../assets/image/ic_select_checkmark.png"),
+ );
imageMap.set(
- ImageKey.dropdownArrow,
- require("../assets/image/ic_dropdown_arrow.png")
- )
+ ImageKey.dropdownArrow,
+ require("../assets/image/ic_dropdown_arrow.png"),
+ );
imageMap.set(
- ImageKey.errorInfo,
- require("../assets/image/ic_error_info.png")
- )
+ ImageKey.errorInfo,
+ require("../assets/image/ic_error_info.png"),
+ );
imageMap.set(
- ImageKey.securityConfirmMain,
- require("../assets/image/ic_security_confirm_main.png")
- )
+ ImageKey.securityConfirmMain,
+ require("../assets/image/ic_security_confirm_main.png"),
+ );
imageMap.set(
- ImageKey.biometricsAllowMain,
- require('../assets/image/ic_biometrics_allow_main.png'),
- )
+ ImageKey.biometricsAllowMain,
+ require("../assets/image/ic_biometrics_allow_main.png"),
+ );
imageMap.set(ImageKey.requestIcon, {
- uri: 'https://avatars.githubusercontent.com/u/37784886',
- })
+ uri: "https://avatars.githubusercontent.com/u/37784886",
+ });
imageMap.set(
- ImageKey.transactionTokenIcon,
- require("../assets/image/ic_usdc.png"),
- )
+ ImageKey.transactionTokenIcon,
+ require("../assets/image/ic_usdc.png"),
+ );
imageMap.set(
- ImageKey.networkFeeTipIcon,
- require("../assets/image/ic_fee_info.png"),
- )
+ ImageKey.networkFeeTipIcon,
+ require("../assets/image/ic_fee_info.png"),
+ );
imageMap.set(
- ImageKey.showLessDetailArrow,
- require("../assets/image/ic_show_less_arrow.png"),
- )
+ ImageKey.showLessDetailArrow,
+ require("../assets/image/ic_show_less_arrow.png"),
+ );
imageMap.set(
- ImageKey.showMoreDetailArrow,
- require("../assets/image/ic_show_more_arrow.png"),
- )
- WalletSdk.setImageMap(imageMap)
-}
+ ImageKey.showMoreDetailArrow,
+ require("../assets/image/ic_show_more_arrow.png"),
+ );
+ WalletSdk.setImageMap(imageMap);
+};
const _setDateFormat = () => {
- WalletSdk.setDateFormat(DateFormat.YYYYMMDD_HYPHEN)
-}
+ WalletSdk.setDateFormat(DateFormat.YYYYMMDD_HYPHEN);
+};
const _setDebugging = () => {
- WalletSdk.setDebugging(true)
-}
+ WalletSdk.setDebugging(true);
+};
const _setCustomUserAgent = () => {
- WalletSdk.setCustomUserAgent("Circle-Programmable-Wallet-RN-Sample")
-}
+ WalletSdk.setCustomUserAgent("Circle-Programmable-Wallet-RN-Sample");
+};
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..4566278
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,9 @@
+const { defineConfig } = require("eslint/config");
+const expoConfig = require("eslint-config-expo/flat");
+
+module.exports = defineConfig([
+ expoConfig,
+ {
+ ignores: ["dist/*"],
+ },
+]);
diff --git a/features/result/resultSlice.ts b/features/result/resultSlice.ts
index d89475e..1310e97 100644
--- a/features/result/resultSlice.ts
+++ b/features/result/resultSlice.ts
@@ -16,22 +16,22 @@
* limitations under the License.
*/
-import { createSlice, PayloadAction } from '@reduxjs/toolkit'
-import type { RootState } from '../../redux/store'
-import { AuthMode } from '../../redux/types'
-import type { LoginResult } from '@circle-fin/w3s-pw-react-native-sdk'
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import type { RootState } from "../../redux/store";
+import { AuthMode } from "../../redux/types";
+import type { LoginResult } from "@circle-fin/w3s-pw-react-native-sdk";
export interface AuthLoginResult {
- authMode: AuthMode,
- result: LoginResult
+ authMode: AuthMode;
+ result: LoginResult;
}
// Define a type for the slice state
interface ResultState {
- emailUserToken?: string | undefined,
- emailEncryptionKey?: string | undefined,
- socialUserToken?: string | undefined,
- socialEncryptionKey?: string | undefined,
+ emailUserToken?: string | undefined;
+ emailEncryptionKey?: string | undefined;
+ socialUserToken?: string | undefined;
+ socialEncryptionKey?: string | undefined;
}
// Define the initial state using that type
@@ -39,39 +39,41 @@ const initialState: ResultState = {
emailEncryptionKey: undefined,
emailUserToken: undefined,
socialEncryptionKey: undefined,
- socialUserToken: undefined
-}
+ socialUserToken: undefined,
+};
export const resultSlice = createSlice({
- name: 'result',
+ name: "result",
initialState,
reducers: {
setLoginResult: (state, action: PayloadAction) => {
- switch (action.payload.authMode){
+ switch (action.payload.authMode) {
case AuthMode.email:
- state.emailUserToken = action.payload.result.userToken
- state.emailEncryptionKey = action.payload.result.encryptionKey
- break
+ state.emailUserToken = action.payload.result.userToken;
+ state.emailEncryptionKey = action.payload.result.encryptionKey;
+ break;
case AuthMode.social:
- state.socialUserToken = action.payload.result.userToken
- state.socialEncryptionKey = action.payload.result.encryptionKey
- break
+ state.socialUserToken = action.payload.result.userToken;
+ state.socialEncryptionKey = action.payload.result.encryptionKey;
+ break;
default:
// Other auth modes (like PIN) don't store tokens/keys
- break
+ break;
}
- }
+ },
},
-})
+});
-export const {
- setLoginResult
-} = resultSlice.actions
+export const { setLoginResult } = resultSlice.actions;
// Other code such as selectors can use the imported `RootState` type
-export const selectEmailUserToken = (state: RootState) => state.result.emailUserToken
-export const selectEmailEncryptionKey = (state: RootState) => state.result.emailEncryptionKey
-export const selectSocialUserToken = (state: RootState) => state.result.socialUserToken
-export const selectSocialEncryptionKey = (state: RootState) => state.result.socialEncryptionKey
+export const selectEmailUserToken = (state: RootState) =>
+ state.result.emailUserToken;
+export const selectEmailEncryptionKey = (state: RootState) =>
+ state.result.emailEncryptionKey;
+export const selectSocialUserToken = (state: RootState) =>
+ state.result.socialUserToken;
+export const selectSocialEncryptionKey = (state: RootState) =>
+ state.result.socialEncryptionKey;
-export default resultSlice.reducer
+export default resultSlice.reducer;
diff --git a/features/settings/settingsSlice.ts b/features/settings/settingsSlice.ts
index 997f69c..7545362 100644
--- a/features/settings/settingsSlice.ts
+++ b/features/settings/settingsSlice.ts
@@ -16,43 +16,41 @@
* limitations under the License.
*/
-import { createSlice, PayloadAction } from '@reduxjs/toolkit'
-import { pw_app_id, pw_endpoint } from '../../src/config.json'
-import type { RootState } from '@redux/store'
-import type { SettingsState } from '@redux/types'
+import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import { pw_app_id, pw_endpoint } from "../../src/config.json";
+import type { RootState } from "@redux/store";
+import type { SettingsState } from "@redux/types";
// Define the initial state using that type
const initialState: SettingsState = {
endpoint: pw_endpoint,
appId: pw_app_id,
- enableBiometrics: false
-}
+ enableBiometrics: false,
+};
export const settingsSlice = createSlice({
- name: 'settings',
+ name: "settings",
initialState,
reducers: {
setEndpoint: (state, action: PayloadAction) => {
- state.endpoint = action.payload
+ state.endpoint = action.payload;
},
setAppId: (state, action: PayloadAction) => {
- state.appId = action.payload
+ state.appId = action.payload;
},
setEnableBiometrics: (state, action: PayloadAction) => {
- state.enableBiometrics = action.payload
+ state.enableBiometrics = action.payload;
},
},
-})
+});
-export const {
- setEndpoint,
- setAppId,
- setEnableBiometrics
-} = settingsSlice.actions
+export const { setEndpoint, setAppId, setEnableBiometrics } =
+ settingsSlice.actions;
// Other code such as selectors can use the imported `RootState` type
-export const selectEndpoint = (state: RootState) => state.settings.endpoint
-export const selectAppId = (state: RootState) => state.settings.appId
-export const selectEnableBiometrics = (state: RootState) => state.settings.enableBiometrics
+export const selectEndpoint = (state: RootState) => state.settings.endpoint;
+export const selectAppId = (state: RootState) => state.settings.appId;
+export const selectEnableBiometrics = (state: RootState) =>
+ state.settings.enableBiometrics;
-export default settingsSlice.reducer
\ No newline at end of file
+export default settingsSlice.reducer;
diff --git a/metro.config.js b/metro.config.js
index ca0f719..a290de0 100644
--- a/metro.config.js
+++ b/metro.config.js
@@ -17,17 +17,17 @@
*/
// Learn more https://docs.expo.io/guides/customizing-metro
-const { getDefaultConfig } = require('expo/metro-config')
-const path = require('path')
+const { getDefaultConfig } = require("expo/metro-config");
+const path = require("path");
-const config = getDefaultConfig(__dirname)
+const config = getDefaultConfig(__dirname);
config.resolver = {
...config.resolver,
extraNodeModules: {
- '@features': path.resolve(__dirname, 'features'),
- '@redux': path.resolve(__dirname, 'redux')
- }
-}
+ "@features": path.resolve(__dirname, "features"),
+ "@redux": path.resolve(__dirname, "redux"),
+ },
+};
-module.exports = config
+module.exports = config;
diff --git a/package-lock.json b/package-lock.json
index 6e22b35..5ee1413 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,14 @@
{
"name": "w3ssamplewallet",
- "version": "1.0.0",
+ "version": "2.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "w3ssamplewallet",
- "version": "1.0.0",
+ "version": "2.1.0",
"dependencies": {
- "@circle-fin/w3s-pw-react-native-sdk": "^2.0.0",
+ "@circle-fin/w3s-pw-react-native-sdk": "^2.2.1",
"@expo/vector-icons": "^15.0.2",
"@react-navigation/bottom-tabs": "^7.2.1",
"@react-navigation/elements": "^2.8.1",
@@ -1543,9 +1543,9 @@
}
},
"node_modules/@circle-fin/w3s-pw-react-native-sdk": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@circle-fin/w3s-pw-react-native-sdk/-/w3s-pw-react-native-sdk-2.0.2.tgz",
- "integrity": "sha512-ieG3quNu+/LpYm58ioK1lxh9PD5wWjbTPbXtWvAtd5+jLppy5LOIbeG62PTfQUdfpY4lECTr/HiCkSUiGA5Bxg==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@circle-fin/w3s-pw-react-native-sdk/-/w3s-pw-react-native-sdk-2.2.1.tgz",
+ "integrity": "sha512-+weBFrEzr5w7n1lshfhRHGDtAVtbXlXL2eqVO/5okRTrFRs7ol4r2HSDODnEdlWRnvDxG4x8eUJmHvYGYtPCNA==",
"license": "Apache-2.0",
"peerDependencies": {
"expo": "*",
@@ -1929,22 +1929,13 @@
"fingerprint": "bin/cli.js"
}
},
- "node_modules/@expo/fingerprint/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/@expo/fingerprint/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -2111,15 +2102,6 @@
}
}
},
- "node_modules/@expo/metro-config/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/@expo/metro-config/node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
@@ -2133,12 +2115,12 @@
}
},
"node_modules/@expo/metro-config/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -3630,24 +3612,14 @@
"typescript": ">=4.8.4 <6.0.0"
}
},
- "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -4700,13 +4672,12 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "2.0.3",
+ "resolved": "https://npm.cloudsmith.io/circle/npm-public/brace-expansion/-/brace-expansion-2.0.3.tgz",
+ "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/braces": {
@@ -5163,12 +5134,6 @@
"node": ">= 0.6"
}
},
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "license": "MIT"
- },
"node_modules/connect": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
@@ -6951,15 +6916,6 @@
"async-limiter": "~1.0.0"
}
},
- "node_modules/expo/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/expo/node_modules/ci-info": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
@@ -6982,12 +6938,12 @@
"license": "MIT"
},
"node_modules/expo/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -6997,9 +6953,9 @@
}
},
"node_modules/expo/node_modules/picomatch": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
- "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz",
+ "integrity": "sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==",
"license": "MIT",
"engines": {
"node": ">=10"
@@ -7302,9 +7258,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
- "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@@ -7597,22 +7553,13 @@
"node": ">=10.13.0"
}
},
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/glob/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -9766,9 +9713,9 @@
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -9915,9 +9862,9 @@
}
},
"node_modules/node-forge": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz",
- "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
+ "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
"license": "(BSD-3-Clause OR GPL-2.0)",
"engines": {
"node": ">= 6.13.0"
@@ -10506,9 +10453,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -12494,9 +12441,9 @@
}
},
"node_modules/tar": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
- "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
+ "version": "7.5.11",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
+ "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
@@ -12644,9 +12591,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -12923,9 +12870,9 @@
}
},
"node_modules/undici": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
- "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
+ "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
"license": "MIT",
"engines": {
"node": ">=18.17"
diff --git a/package.json b/package.json
index 459f396..1499e59 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "w3ssamplewallet",
"main": "expo-router/entry",
"packageManager": "npm@10.8.2",
- "version": "1.0.0",
+ "version": "2.1.0",
"scripts": {
"start": "expo start",
"android": "expo run:android",
@@ -12,7 +12,7 @@
"format": "npx --yes prettier --write ."
},
"dependencies": {
- "@circle-fin/w3s-pw-react-native-sdk": "^2.0.0",
+ "@circle-fin/w3s-pw-react-native-sdk": "^2.2.1",
"@expo/vector-icons": "^15.0.2",
"@react-navigation/bottom-tabs": "^7.2.1",
"@react-navigation/elements": "^2.8.1",
@@ -54,11 +54,10 @@
"typescript": "~5.9.2"
},
"overrides": {
- "node-forge": "1.3.2",
"glob": "10.5.0",
- "undici": "6.23.0",
"js-yaml": "4.1.1",
- "tar": "7.5.7"
+ "tar": "7.5.11",
+ "brace-expansion": "2.0.3"
},
"private": true
}
diff --git a/redux/hooks.ts b/redux/hooks.ts
index 3358dfe..2727933 100644
--- a/redux/hooks.ts
+++ b/redux/hooks.ts
@@ -16,9 +16,9 @@
* limitations under the License.
*/
-import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
-import type { RootState, AppDispatch } from './store'
+import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
+import type { RootState, AppDispatch } from "./store";
// Use throughout your app instead of plain `useDispatch` and `useSelector`
-export const useAppDispatch = () => useDispatch()
-export const useAppSelector: TypedUseSelectorHook = useSelector
+export const useAppDispatch = () => useDispatch();
+export const useAppSelector: TypedUseSelectorHook = useSelector;
diff --git a/redux/store.ts b/redux/store.ts
index 0ba6072..e39fa25 100644
--- a/redux/store.ts
+++ b/redux/store.ts
@@ -16,16 +16,16 @@
* limitations under the License.
*/
-import { configureStore } from '@reduxjs/toolkit'
-import settingsReducer from '@features/settings/settingsSlice'
-import resultReducer from '@features/result/resultSlice'
+import { configureStore } from "@reduxjs/toolkit";
+import settingsReducer from "@features/settings/settingsSlice";
+import resultReducer from "@features/result/resultSlice";
export const store = configureStore({
reducer: {
settings: settingsReducer,
result: resultReducer,
},
-})
+});
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType;
diff --git a/redux/types.ts b/redux/types.ts
index 053498e..ecead54 100644
--- a/redux/types.ts
+++ b/redux/types.ts
@@ -17,9 +17,9 @@
*/
export enum AuthMode {
- social = 'social',
- email = 'email',
- pin = 'pin',
+ social = "social",
+ email = "email",
+ pin = "pin",
}
export interface SettingsState {
diff --git a/styles.ts b/styles.ts
index 8f08ce4..056a34e 100644
--- a/styles.ts
+++ b/styles.ts
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import { StyleSheet } from "react-native"
+import { StyleSheet } from "react-native";
export const colors = {
text_main: "#1A1A1A",
@@ -53,14 +53,14 @@ export const colors = {
snackbar_success_bg: "#008339",
snackbar_error_bg: "#FFEAEF",
snackbar_error_text: "#BC0016",
-}
+};
-export const pagePaddingH = 16
+export const pagePaddingH = 16;
export const commonStyles = StyleSheet.create({
container: {
flex: 1,
- backgroundColor: colors.background
+ backgroundColor: colors.background,
},
containerWithPadding: {
flex: 1,
@@ -75,7 +75,7 @@ export const commonStyles = StyleSheet.create({
borderRadius: 56,
minHeight: 56,
paddingVertical: 8,
- justifyContent: "center"
+ justifyContent: "center",
},
secondaryButton: {
marginTop: 24,
@@ -86,46 +86,46 @@ export const commonStyles = StyleSheet.create({
borderRadius: 56,
minHeight: 56,
paddingVertical: 8,
- justifyContent: "center"
+ justifyContent: "center",
},
disabledMainButton: {
- backgroundColor: colors.disabled_main_bt_background
+ backgroundColor: colors.disabled_main_bt_background,
},
disabledSecondaryButton: {
backgroundColor: colors.disabled_secondary_bt_background,
- opacity: 0.5
+ opacity: 0.5,
},
disabledMainButtonText: {
- color: colors.disabled_main_bt_text
+ color: colors.disabled_main_bt_text,
},
disabledSecondaryButtonText: {
- color: colors.disabled_secondary_bt_text
+ color: colors.disabled_secondary_bt_text,
},
mainButtonText: {
color: colors.main_bt_text,
fontWeight: "500",
- fontSize: 16
+ fontSize: 16,
},
secondaryButtonText: {
color: colors.primary,
fontWeight: "500",
- fontSize: 16
+ fontSize: 16,
},
sectionLine: {
height: 1,
backgroundColor: colors.section_line,
flexShrink: 1,
- alignSelf: 'center',
- flex: 1
+ alignSelf: "center",
+ flex: 1,
},
sectionText: {
color: colors.section_text,
- textAlign: 'center',
+ textAlign: "center",
fontWeight: "400",
fontSize: 14,
marginHorizontal: 16,
- alignSelf: 'center',
- justifyContent: 'center',
+ alignSelf: "center",
+ justifyContent: "center",
},
inputTitle: {
color: colors.text_auxiliary,
@@ -139,28 +139,28 @@ export const commonStyles = StyleSheet.create({
color: colors.text_main,
fontWeight: "400",
fontSize: 16,
- marginTop: 0
+ marginTop: 0,
},
tabText: {
color: colors.tab_focused,
fontSize: 14,
- fontWeight: "600"
+ fontWeight: "600",
},
heading: {
color: colors.text_main,
fontSize: 22,
fontWeight: "600",
marginTop: 24,
- textAlign: 'center',
- paddingHorizontal: pagePaddingH
+ textAlign: "center",
+ paddingHorizontal: pagePaddingH,
},
desc: {
color: colors.text_desc,
fontSize: 14,
marginTop: 16,
marginBottom: 24,
- textAlign: 'center',
- paddingHorizontal: pagePaddingH
+ textAlign: "center",
+ paddingHorizontal: pagePaddingH,
},
normalInputField: {
marginTop: 8,
@@ -172,7 +172,7 @@ export const commonStyles = StyleSheet.create({
paddingVertical: 8,
color: colors.text_main,
fontWeight: "400",
- fontSize: 16
+ fontSize: 16,
},
normalValueText: {
color: colors.text_main,
@@ -181,21 +181,21 @@ export const commonStyles = StyleSheet.create({
marginTop: 8,
marginBottom: 4,
minHeight: 24,
- flexShrink: 1
+ flexShrink: 1,
},
disabledInputField: {
borderColor: colors.input_boarder,
- backgroundColor: colors.disabled_input_background
+ backgroundColor: colors.disabled_input_background,
},
focusedInputField: {
- borderColor: colors.input_boarder_focused
+ borderColor: colors.input_boarder_focused,
},
requiredMark: {
color: colors.required_red,
- borderColor: 'red',
+ borderColor: "red",
fontWeight: "400",
fontSize: 12,
marginLeft: 4,
- flexWrap: 'wrap'
+ flexWrap: "wrap",
},
-})
+});
diff --git a/tsconfig.json b/tsconfig.json
index 3eade30..2e54598 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,21 +4,10 @@
"strict": true,
"jsx": "react-native",
"paths": {
- "@/*": [
- "./*"
- ],
- "@features/*": [
- "./features/*"
- ],
- "@redux/*": [
- "./redux/*"
- ]
+ "@/*": ["./*"],
+ "@features/*": ["./features/*"],
+ "@redux/*": ["./redux/*"]
}
},
- "include": [
- "**/*.ts",
- "**/*.tsx",
- ".expo/types/**/*.ts",
- "expo-env.d.ts"
- ]
+ "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
diff --git a/utils/i18n.ts b/utils/i18n.ts
index 4ed09d2..cd9f51a 100644
--- a/utils/i18n.ts
+++ b/utils/i18n.ts
@@ -16,81 +16,81 @@
* limitations under the License.
*/
-import { default as i18next } from 'i18next'
-import { initReactI18next } from 'react-i18next'
+import { default as i18next } from "i18next";
+import { initReactI18next } from "react-i18next";
const resources = {
en: {
translation: {
- tab_social: 'Social',
- tab_email: 'Email',
- tab_pin: 'PIN',
- login: 'Login',
- register: 'Register',
- email: 'Email',
- password: 'Password',
- pin: 'PIN',
- confirm_pin: 'Confirm PIN',
- submit: 'Submit',
- back: 'Back',
- social_login_title: 'Social Login',
- email_login_title: 'Email Login',
- pin_login_title: 'PIN Login',
- sdk_version: 'SDK Version',
- required_mark: '*',
- endpoint_title: 'Endpoint',
- appid_title: 'App ID',
- user_token_title: 'User Token',
- encryption_title: 'Encryption Key',
- challenge_id_title: 'Challenge ID',
- execute_bt: 'Execute',
- set_biometrics_pin_bt: 'Set Biometrics PIN',
- biometrics_switch_title: 'Enable Biometrics',
- biometrics_switch_desc: 'Use biometrics for authentication',
- execute_success: 'Execute Success',
- execute_screen_title: 'Execute Screen',
- received_pin: 'Received PIN',
- go_back: 'Go Back',
- device_id_title: 'Device ID',
- device_token_title: 'Device Token',
- device_encryption_title: 'Device Encryption Key',
- log_in_with_section: 'Log in with',
- login_success: 'Login Success',
- info_full_text: 'Learn more about social login here',
- info_link_text: 'here',
- go_execute_bt: 'Go to Execute',
- go_execute_bt_desc: 'Execute challenges with your user token',
- otp_token_title: 'OTP Token',
- email_login_bt: 'Email Login',
+ tab_social: "Social",
+ tab_email: "Email",
+ tab_pin: "PIN",
+ login: "Login",
+ register: "Register",
+ email: "Email",
+ password: "Password",
+ pin: "PIN",
+ confirm_pin: "Confirm PIN",
+ submit: "Submit",
+ back: "Back",
+ social_login_title: "Social Login",
+ email_login_title: "Email Login",
+ pin_login_title: "PIN Login",
+ sdk_version: "SDK Version",
+ required_mark: "*",
+ endpoint_title: "Endpoint",
+ appid_title: "App ID",
+ user_token_title: "User Token",
+ encryption_title: "Encryption Key",
+ challenge_id_title: "Challenge ID",
+ execute_bt: "Execute",
+ set_biometrics_pin_bt: "Set Biometrics PIN",
+ biometrics_switch_title: "Enable Biometrics",
+ biometrics_switch_desc: "Use biometrics for authentication",
+ execute_success: "Execute Success",
+ execute_screen_title: "Execute Screen",
+ received_pin: "Received PIN",
+ go_back: "Go Back",
+ device_id_title: "Device ID",
+ device_token_title: "Device Token",
+ device_encryption_title: "Device Encryption Key",
+ log_in_with_section: "Log in with",
+ login_success: "Login Success",
+ info_full_text: "Learn more about social login here",
+ info_link_text: "here",
+ go_execute_bt: "Go to Execute",
+ go_execute_bt_desc: "Execute challenges with your user token",
+ otp_token_title: "OTP Token",
+ email_login_bt: "Email Login",
main_title: "User Controlled Wallet \nSample App",
main_subtitle: "Choose one Auth Method to start",
- implement_callback_instruction: 'Callback received',
- google_bt: 'Continue with Google',
- facebook_bt: 'Continue with Facebook',
- apple_bt: 'Continue with Apple',
- }
- }
-}
+ implement_callback_instruction: "Callback received",
+ google_bt: "Continue with Google",
+ facebook_bt: "Continue with Facebook",
+ apple_bt: "Continue with Apple",
+ },
+ },
+};
i18next
.use(initReactI18next)
.init({
resources,
- lng: 'en',
- fallbackLng: 'en',
+ lng: "en",
+ fallbackLng: "en",
interpolation: {
- escapeValue: false
- }
+ escapeValue: false,
+ },
})
.then(() => {
- console.log('i18next initialized successfully')
- })
- .catch(error => {
- console.error('Error initializing i18next:', error)
+ console.log("i18next initialized successfully");
})
+ .catch((error) => {
+ console.error("Error initializing i18next:", error);
+ });
export const t = (key: string): string => {
- return i18next.t(key)
-}
+ return i18next.t(key);
+};
-export default i18next
\ No newline at end of file
+export default i18next;
diff --git a/utils/useSnackBar.tsx b/utils/useSnackBar.tsx
index 2493e09..d201fe7 100644
--- a/utils/useSnackBar.tsx
+++ b/utils/useSnackBar.tsx
@@ -16,24 +16,24 @@
* limitations under the License.
*/
-import { useState } from 'react'
+import { useState } from "react";
export type ShowSnackBarFn = (msg: string, isSuccess?: boolean) => void;
export const useSnackBar = () => {
- const [visible, setVisible] = useState(false)
- const [message, setMessage] = useState('')
- const [isSuccess, setIsSuccess] = useState(true)
+ const [visible, setVisible] = useState(false);
+ const [message, setMessage] = useState("");
+ const [isSuccess, setIsSuccess] = useState(true);
const showSnackBar = (msg: string, success: boolean = true) => {
- setMessage(msg)
- setIsSuccess(success)
- setVisible(true)
- }
+ setMessage(msg);
+ setIsSuccess(success);
+ setVisible(true);
+ };
const hideSnackBar = () => {
- setVisible(false)
- }
+ setVisible(false);
+ };
return {
visible,
@@ -41,5 +41,5 @@ export const useSnackBar = () => {
isSuccess,
showSnackBar,
hideSnackBar,
- }
-}
+ };
+};
diff --git a/utils/useWalletSdk.ts b/utils/useWalletSdk.ts
index 777ed62..bf47ba8 100644
--- a/utils/useWalletSdk.ts
+++ b/utils/useWalletSdk.ts
@@ -22,105 +22,160 @@ import {
SuccessCallback,
LoginSuccessCallback,
SocialProvider,
- LoginResult
-} from "@circle-fin/w3s-pw-react-native-sdk"
-import { ShowSnackBarFn } from "./useSnackBar"
-import { useAppSelector, useAppDispatch } from "../redux/hooks"
+ LoginResult,
+} from "@circle-fin/w3s-pw-react-native-sdk";
+import { ShowSnackBarFn } from "./useSnackBar";
+import { useAppSelector, useAppDispatch } from "../redux/hooks";
import {
setEndpoint as setReduxEndpoint,
setAppId as setReduxAppId,
- setEnableBiometrics as setReduxEnableBiometrics
-} from "../features/settings/settingsSlice"
-import { setLoginResult } from "../features/result/resultSlice"
-import { AuthMode } from "../redux/types"
+ setEnableBiometrics as setReduxEnableBiometrics,
+} from "../features/settings/settingsSlice";
+import { setLoginResult } from "../features/result/resultSlice";
+import { AuthMode } from "../redux/types";
export default function useWalletSdk(showSnackBar: ShowSnackBarFn) {
- const dispatch = useAppDispatch()
- const endpoint = useAppSelector(state => state.settings.endpoint)
- const appId = useAppSelector(state => state.settings.appId)
- const enableBiometricsPin = useAppSelector(state => state.settings.enableBiometrics)
+ const dispatch = useAppDispatch();
+ const endpoint = useAppSelector((state) => state.settings.endpoint);
+ const appId = useAppSelector((state) => state.settings.appId);
+ const enableBiometricsPin = useAppSelector(
+ (state) => state.settings.enableBiometrics,
+ );
const dispatchEndpoint = (value: string) => {
- dispatch(setReduxEndpoint(value))
- }
+ dispatch(setReduxEndpoint(value));
+ };
const dispatchAppId = (value: string) => {
- dispatch(setReduxAppId(value))
- }
+ dispatch(setReduxAppId(value));
+ };
const dispatchEnableBiometrics = (value: boolean) => {
- dispatch(setReduxEnableBiometrics(value))
- }
+ dispatch(setReduxEnableBiometrics(value));
+ };
const initThen = (action: () => void) => {
WalletSdk.init({
endpoint,
appId,
- settingsManagement: { enableBiometricsPin: enableBiometricsPin }
- }).then(() => {
- action()
- }).catch((e) => {
- showSnackBar(e.message, false)
+ settingsManagement: { enableBiometricsPin: enableBiometricsPin },
})
- }
+ .then(() => {
+ action();
+ })
+ .catch((e) => {
+ showSnackBar(e?.message || "Unknown error", false);
+ });
+ };
- const verifyOtp = (otpToken: string, deviceToken: string, deviceEncryptionKey: string,
+ const verifyOtp = (
+ otpToken: string,
+ deviceToken: string,
+ deviceEncryptionKey: string,
successCallback: LoginSuccessCallback,
- errorCallback: ErrorCallback) => {
+ errorCallback: ErrorCallback,
+ ) => {
initThen(() => {
- WalletSdk.verifyOTP(otpToken, deviceToken, deviceEncryptionKey, successCallback, errorCallback)
- })
- }
+ WalletSdk.verifyOTP(
+ otpToken,
+ deviceToken,
+ deviceEncryptionKey,
+ successCallback,
+ errorCallback,
+ );
+ });
+ };
- const logoutAndLogin = (provider: SocialProvider, deviceToken: string, deviceEncryptionKey: string,
+ const logoutAndLogin = (
+ provider: SocialProvider,
+ deviceToken: string,
+ deviceEncryptionKey: string,
successCallback: LoginSuccessCallback,
- errorCallback: ErrorCallback) => {
+ errorCallback: ErrorCallback,
+ ) => {
initThen(() => {
- WalletSdk.performLogin(provider, deviceToken, deviceEncryptionKey, successCallback, errorCallback)
- })
- }
+ WalletSdk.performLogin(
+ provider,
+ deviceToken,
+ deviceEncryptionKey,
+ successCallback,
+ errorCallback,
+ );
+ });
+ };
- const execute = (userToken: string, encryptionKey: string, challengeId: string,
+ const execute = (
+ userToken: string,
+ encryptionKey: string,
+ challengeId: string,
successCallback: SuccessCallback,
- errorCallback: ErrorCallback) => {
+ errorCallback: ErrorCallback,
+ ) => {
initThen(() => {
- WalletSdk.execute(userToken, encryptionKey, [challengeId], successCallback, errorCallback)
- })
- }
+ WalletSdk.execute(
+ userToken,
+ encryptionKey,
+ [challengeId],
+ successCallback,
+ errorCallback,
+ );
+ });
+ };
- const setBiometricsPin = (userToken: string, encryptionKey: string,
+ const setBiometricsPin = (
+ userToken: string,
+ encryptionKey: string,
successCallback: SuccessCallback,
- errorCallback: ErrorCallback) => {
+ errorCallback: ErrorCallback,
+ ) => {
initThen(() => {
- WalletSdk.setBiometricsPin(userToken, encryptionKey, successCallback, errorCallback)
- })
- }
+ WalletSdk.setBiometricsPin(
+ userToken,
+ encryptionKey,
+ successCallback,
+ errorCallback,
+ );
+ });
+ };
const dispatchLoginResult = (authMode: AuthMode, result: LoginResult) => {
- dispatch(setLoginResult({ authMode, result }))
- }
-
+ dispatch(setLoginResult({ authMode, result }));
+ };
// Get authentication data from Redux state
- const emailUserToken = useAppSelector(state => state.result.emailUserToken)
- const emailEncryptionKey = useAppSelector(state => state.result.emailEncryptionKey)
- const socialUserToken = useAppSelector(state => state.result.socialUserToken)
- const socialEncryptionKey = useAppSelector(state => state.result.socialEncryptionKey)
-
+ const emailUserToken = useAppSelector((state) => state.result.emailUserToken);
+ const emailEncryptionKey = useAppSelector(
+ (state) => state.result.emailEncryptionKey,
+ );
+ const socialUserToken = useAppSelector(
+ (state) => state.result.socialUserToken,
+ );
+ const socialEncryptionKey = useAppSelector(
+ (state) => state.result.socialEncryptionKey,
+ );
+
return {
// Configuration
- endpoint, appId, enableBiometricsPin,
-
+ endpoint,
+ appId,
+ enableBiometricsPin,
+
// Redux action dispatchers
- dispatchEndpoint, dispatchAppId, dispatchEnableBiometrics,
-
+ dispatchEndpoint,
+ dispatchAppId,
+ dispatchEnableBiometrics,
+
// SDK methods
- execute, setBiometricsPin, logoutAndLogin, dispatchLoginResult, verifyOtp,
-
+ execute,
+ setBiometricsPin,
+ logoutAndLogin,
+ dispatchLoginResult,
+ verifyOtp,
+
// Auth data
- emailUserToken, emailEncryptionKey,
- socialUserToken, socialEncryptionKey
- }
+ emailUserToken,
+ emailEncryptionKey,
+ socialUserToken,
+ socialEncryptionKey,
+ };
}
-
-