# Enabling Elements in React Native
Like other platforms, React requires the same two or three simple steps: Add a web view, handle events/messages, and, in some cases, authenticate the user.
## Step 1. Set Up a Web View
Component used: [WebView](https://www.npmjs.com/package/react-native-webview)
Required Web View Configuration
- Enable JavaScript
- Enable Web Storage (DOM Storage)
#### Web View Sample
elements-in-react.tsx
// Step 1: Setup a "web view"
DailyPay Elements
Log:
{logMessages}
Type:
Payload (JSON):
## Step 2. Set Up Event/Message Handling
### Sending Events
Method used: [postMessage](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md#postmessagestr)
#### Send Message Sample Code
elements-in-react.tsx
// Step 2: Setup Communications: Event/Message Handling
// Step 2a: Send Event to Elements
const sendMessageToElement = (type: string, payload: object) => {
const message = { type: type, payload: payload };
if (dpElementWebView.current) {
dpElementWebView.current.postMessage(JSON.stringify(message), dpElementOrigin);
setLogMessages(
(prevMessages) =>
"Sent: " + JSON.stringify(message) + "\n" + prevMessages,
);
}
};
### Listening for Events
Property used: [onMessage](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md#onmessage)
#### Receive Message Sample Code
elements-in-react.tsx
// Step 2b: Listen for events from Elements
const handleMessageFromElement = (event: WebViewMessageEvent) => {
const receivedEvent = event.nativeEvent;
// Log the raw event for debugging and illustration
console.log("Raw event received:", receivedEvent);
// It is crucial to verify the origin of the message for security reasons.
if (receivedEvent.url.startsWith(dpElementOrigin) === false) {
console.warn("Received message from unknown origin:", receivedEvent.url);
return;
}
// Parse the received data - it should be a JSON formatted string
let receivedMessage;
try {
receivedMessage = JSON.parse(receivedEvent.data);
} catch (e) {
console.error("Invalid JSON in payload input:", e);
return;
}
console.log("Message from WebView:", receivedMessage);
if (receivedMessage && receivedMessage.type) {
setLogMessages(
(prevMessages) =>
"Received: " + JSON.stringify(receivedMessage) + "\n" + prevMessages,
);
switch (receivedMessage.type) {
case "DAILYPAY_CARD_TOKENIZE_RESPONSE":
console.log("DAILYPAY_CARD_TOKENIZE_RESPONSE received: ", receivedMessage.success);
console.log("DAILYPAY_CARD_TOKENIZE_RESPONSE received: ", receivedMessage.response);
// Call API create account function
break;
case "EXT_LOG":
// Log if needed
console.log("EXT_LOG received: ", receivedMessage.payload);
break;
case "EXT_NEED_AUTH":
console.log("EXT_NEED_AUTH received: ", receivedMessage.payload);
handleExtNeedAuth();
break;
default:
console.log("Unhandled event type: ", receivedMessage.type);
}
}
};
## Step 3. Set Up User Authentication (Optional)
Authentication Message Sample Code:
elements-in-react.tsx
// Step 3: Setup Authentication
var dpAuthTokens: AuthorizeResult | RefreshResult | null = null;
const dpAuthConfig: AuthConfiguration = {
issuer: 'https://auth.uat.dailypay.com',
clientId: 'REPLACE_WITH_YOUR_OAUTH_CLIENT_ID',
redirectUrl: 'REPLACE_WITH_YOUR_APP_REDIRECT_URI',
scopes: ['user:read'],
serviceConfiguration: {
authorizationEndpoint: 'https://auth.uat.dailypay.com/oauth2/auth',
tokenEndpoint: 'https://auth.uat.dailypay.com/oauth2/token',
},
};
const dpAuthenticateUser = async () => {
try {
const dpAuthTokens: AuthorizeResult = await authorize(dpAuthConfig);
console.log('Authorization successful:', dpAuthTokens);
// Save token in secure storage
await SecureStore.setItemAsync('dpAuthTokens', JSON.stringify(dpAuthTokens));
// Send token to WebView
sendMessageToElement('GIVE_TOKEN', { token: dpAuthTokens.accessToken });
} catch (error) {
console.error('Authorization failed:', error);
dpAuthTokens = null;
// Handle authentication errors
}
};
const handleExtNeedAuth = async () => {
// Check secure storage for existing tokens
let dpAuthTokensString = await SecureStore.getItemAsync('dpAuthTokens');
if (dpAuthTokensString) {
dpAuthTokens = JSON.parse(dpAuthTokensString);
console.log('Found existing tokens:', dpAuthTokens);
// Check if token is expired
if (dpAuthTokens && dpAuthTokens.refreshToken && Date.parse(dpAuthTokens.accessTokenExpirationDate) < Date.now()) {
try{
dpAuthTokens = await refresh(dpAuthConfig, {
refreshToken: dpAuthTokens.refreshToken,
});
console.log('Token refresh successful:', dpAuthTokens);
await SecureStore.setItemAsync('dpAuthTokens', JSON.stringify(dpAuthTokens));
} catch (error) {
console.warn('Token refresh failed:', error);
dpAuthTokens = null;
dpAuthenticateUser();
};
};
} else {
console.log('No tokens found, initiating login.');
dpAuthenticateUser();
};
if (dpAuthTokens) {
console.log(dpAuthTokens)
sendMessageToElement('GIVE_TOKEN', { token: dpAuthTokens.accessToken });
} else {
console.warn('No valid tokens available, user needs to log in.');
};
};
## Full Sample Code
elements-in-react.tsx
import * as SecureStore from 'expo-secure-store';
import React, { useRef, useState } from "react";
import {
Button,
ScrollView,
StyleSheet,
Text,
TextInput,
View,
} from "react-native";
import { AuthConfiguration, authorize, AuthorizeResult, refresh, RefreshResult } from 'react-native-app-auth';
import { WebView, WebViewMessageEvent } from "react-native-webview";
export default function Index() {
const dpElementOrigin = 'https://elements/uat.dailypay.com';
const dpElementUrl = new URL(dpElementOrigin + '/v1/available-earnings');
dpElementUrl.searchParams.append('client_id', 'REPLACE_WITH_YOUR_CLIENT_ID');
dpElementUrl.searchParams.append('implementation_id', 'REPLACE_WITH_YOUR_IMPLEMENTATION_ID');
// Not required but useful during development to avoid caching issues
dpElementUrl.searchParams.append('cache_bust', Date.now().toString());
const dpElementWebView = useRef(null);
const [inputMessageType, setInputMessageType] = useState("GIVE_TOKEN");
const [inputMessagePayload, setInputMessagePayload] =
useState('{ "token": "" }');
const [logMessages, setLogMessages] = useState("");
// Step 3: Setup Authentication
var dpAuthTokens: AuthorizeResult | RefreshResult | null = null;
const dpAuthConfig: AuthConfiguration = {
issuer: 'https://auth.uat.dailypay.com',
clientId: 'REPLACE_WITH_YOUR_OAUTH_CLIENT_ID',
redirectUrl: 'REPLACE_WITH_YOUR_APP_REDIRECT_URI',
scopes: ['user:read'],
serviceConfiguration: {
authorizationEndpoint: 'https://auth.uat.dailypay.com/oauth2/auth',
tokenEndpoint: 'https://auth.uat.dailypay.com/oauth2/token',
},
};
const dpAuthenticateUser = async () => {
try {
const dpAuthTokens: AuthorizeResult = await authorize(dpAuthConfig);
console.log('Authorization successful:', dpAuthTokens);
// Save token in secure storage
await SecureStore.setItemAsync('dpAuthTokens', JSON.stringify(dpAuthTokens));
// Send token to WebView
sendMessageToElement('GIVE_TOKEN', { token: dpAuthTokens.accessToken });
} catch (error) {
console.error('Authorization failed:', error);
dpAuthTokens = null;
// Handle authentication errors
}
};
const handleExtNeedAuth = async () => {
// Check secure storage for existing tokens
let dpAuthTokensString = await SecureStore.getItemAsync('dpAuthTokens');
if (dpAuthTokensString) {
dpAuthTokens = JSON.parse(dpAuthTokensString);
console.log('Found existing tokens:', dpAuthTokens);
// Check if token is expired
if (dpAuthTokens && dpAuthTokens.refreshToken && Date.parse(dpAuthTokens.accessTokenExpirationDate) < Date.now()) {
try{
dpAuthTokens = await refresh(dpAuthConfig, {
refreshToken: dpAuthTokens.refreshToken,
});
console.log('Token refresh successful:', dpAuthTokens);
await SecureStore.setItemAsync('dpAuthTokens', JSON.stringify(dpAuthTokens));
} catch (error) {
console.warn('Token refresh failed:', error);
dpAuthTokens = null;
dpAuthenticateUser();
};
};
} else {
console.log('No tokens found, initiating login.');
dpAuthenticateUser();
};
if (dpAuthTokens) {
console.log(dpAuthTokens)
sendMessageToElement('GIVE_TOKEN', { token: dpAuthTokens.accessToken });
} else {
console.warn('No valid tokens available, user needs to log in.');
};
};
// Step 3 End
// Step 2: Setup Communications: Event/Message Handling
// Step 2a: Send Event to Elements
const sendMessageToElement = (type: string, payload: object) => {
const message = { type: type, payload: payload };
if (dpElementWebView.current) {
dpElementWebView.current.postMessage(JSON.stringify(message), dpElementOrigin);
setLogMessages(
(prevMessages) =>
"Sent: " + JSON.stringify(message) + "\n" + prevMessages,
);
}
};
// Step 2b: Listen for events from Elements
const handleMessageFromElement = (event: WebViewMessageEvent) => {
const receivedEvent = event.nativeEvent;
// Log the raw event for debugging and illustration
console.log("Raw event received:", receivedEvent);
// It is crucial to verify the origin of the message for security reasons.
if (receivedEvent.url.startsWith(dpElementOrigin) === false) {
console.warn("Received message from unknown origin:", receivedEvent.url);
return;
}
// Parse the received data - it should be a JSON formatted string
let receivedMessage;
try {
receivedMessage = JSON.parse(receivedEvent.data);
} catch (e) {
console.error("Invalid JSON in payload input:", e);
return;
}
console.log("Message from WebView:", receivedMessage);
if (receivedMessage && receivedMessage.type) {
setLogMessages(
(prevMessages) =>
"Received: " + JSON.stringify(receivedMessage) + "\n" + prevMessages,
);
switch (receivedMessage.type) {
case "DAILYPAY_CARD_TOKENIZE_RESPONSE":
console.log("DAILYPAY_CARD_TOKENIZE_RESPONSE received: ", receivedMessage.success);
console.log("DAILYPAY_CARD_TOKENIZE_RESPONSE received: ", receivedMessage.response);
// Call API create account function
break;
case "EXT_LOG":
// Log if needed
console.log("EXT_LOG received: ", receivedMessage.payload);
break;
case "EXT_NEED_AUTH":
console.log("EXT_NEED_AUTH received: ", receivedMessage.payload);
handleExtNeedAuth();
break;
default:
console.log("Unhandled event type: ", receivedMessage.type);
}
}
};
// Step 2 End
return (
// Step 1: Setup a "web view"
DailyPay Elements
Log:
{logMessages}
Type:
Payload (JSON):
// Step 1 End
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#25292e",
justifyContent: "center",
alignItems: "center",
},
input: {
height: 40,
borderWidth: 1,
padding: 10,
width: 200,
backgroundColor: "#fff",
},
text: {
color: "#fff",
},
webview: {
width: 380,
height: 180,
borderRadius: 10,
overflow: 'hidden',
},
});