React Native Cloud Account Information
How can we get the information for a specific cloud account?
These code snippets demonstrate how the React Native application gets the cloud account information for a particular user and a particular cloud account. Note that this code will NOT succeed unless a valid Rosetta JWT is presented at the API endpoint along with this request. Also note that a cloud account is synonymous with a target site...the idea is that users are targeting the sites where their cloud accounts exist.
--
screens/SelectSite.js
--
import React from 'react';
import { FlatList, TouchableHighlight, View } from 'react-native';
import {
Body,
Button,
Container,
Content,
Footer,
Header,
Item,
Left,
Right,
Title,
Text,
} from 'native-base';
import { connect } from 'react-redux';
import {
targetSiteSelectTargetAndPreloadSiteSpec,
} from '../redux/actions-targetSite';
function SiteItem({ siteSpec, onPressHandler }) {
return (
<TouchableHighlight
key={siteSpec.siteId}
onPress={() => onPressHandler(siteSpec)}
>
<View style={{ padding: 20 }}>
<Text>{siteSpec.siteName}</Text>
</View>
</TouchableHighlight>
);
}
function SelectSite(props) {
const { navigation } = props;
const handleNext = () => {
navigation.navigate('CopyInfo');
}
const handlePrev = () => {
navigation.navigate('SetPasscode');
}
const handleSelectSite = (siteSpec) => {
props.targetSiteSelectTargetAndPreloadSiteSpec(siteSpec);
}
const isSiteSelected = () => {
return props.selectedSiteSpec != null && props.selectedSiteSpec.siteId != null;
}
// Problem if FlatList enclosed within Content and NativeBase List really slow
return (
<Container>
<Header>
<Body>
<Title>{ props.selectedSiteSpec.siteName || 'N/A' }</Title>
</Body>
</Header>
<FlatList
data={props.siteSpecs}
renderItem={ ({ item }) => <SiteItem siteSpec={item} onPressHandler={handleSelectSite} /> }
keyExtractor={ item => item.siteId }
/>
<Footer>
<Item>
<Button onPress={() => handlePrev()} >
<Text>Prev</Text>
</Button>
</Item>
<Item>
<Button disabled={!isSiteSelected()} onPress={() => handleNext()} >
<Text>Next</Text>
</Button>
</Item>
</Footer>
</Container>
);
}
const mapStateToProps = (state /*, ownProps*/) => {
return {
selectedSiteSpec: state.targetSiteReducer.selectedTargetSiteSpec,
siteSpecs: state.targetSiteReducer.potentialTargetSiteSpecs,
}
}
const mapDispatchToProps = {
targetSiteSelectTargetAndPreloadSiteSpec,
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SelectSite)
--
redux/actions-targetSite.js
--
import {
TARGET_SITE_SELECT_TARGET,
} from './actionTypes'
import { targetPasswordLoadSpec } from './actions-common'
export function targetSiteSelectTarget(selectedTargetSiteSpec) {
return { type: TARGET_SITE_SELECT_TARGET, selectedTargetSiteSpec }
}
export function targetSiteSelectTargetAndPreloadSiteSpec(selectedTargetSiteSpec) {
return (dispatch) => {
dispatch(targetSiteSelectTarget(selectedTargetSiteSpec));
dispatch(targetPasswordLoadSpec(selectedTargetSiteSpec.siteId));
};
}
--
redux/actions-common.js
--
import axios from 'axios'
import { isTokenExpired } from './utility'
import {
SERVER_TOKEN_SET_TOKEN_EXPIRED,
TARGET_PASSWORD_LOAD_SPEC_STARTED,
TARGET_PASSWORD_LOAD_SPEC_SUCCESS,
TARGET_PASSWORD_LOAD_SPEC_ERROR,
} from './actionTypes'
import { cryptoCreateHash } from './utility'
// Common
export function commonIsTranslateTokenExpired(state) {
return isTokenExpired(state.serverTokenReducer.serverTokenExpirationSeconds);
}
export function serverTokenSetTokenExpired() {
return { type: SERVER_TOKEN_SET_TOKEN_EXPIRED }
}
// Target Password related
export function targetPasswordLoadSpec(siteId) {
return (dispatch, getState) => {
// guard clause - translate token already expired
if (commonIsTranslateTokenExpired(getState())) {
dispatch(serverTokenSetTokenExpired());
return;
}
dispatch(targetPasswordLoadSpecStarted());
const axiosClient = commonCreateAxiosClientWithTranslateToken(getState());
axiosClient
.get("/api/target-sites/" + siteId)
.then(res => { dispatch(targetPasswordLoadSpecProcess(res.data)); })
.catch(err => { dispatch(targetPasswordLoadSpecError(err.response)); });
};
}
// Helper Functions
function commonCreateAxiosClientWithTranslateToken(state) {
const axiosClient = axios.create();
axiosClient.defaults.baseURL = state.serverTokenReducer.serverBaseUri;
axiosClient.defaults.headers.common['Authorization'] = "Bearer " + state.serverTokenReducer.serverTokenValue;
axiosClient.defaults.headers.common['X-Device-Id'] = state.serverTokenReducer.deviceId;
return axiosClient;
}
async function targetPasswordCreatePasswordHash(passwordValue, selectedTargetSiteInfo) {
// guard clause - invalid input
if (selectedTargetSiteInfo == null || selectedTargetSiteInfo.siteSalt == null) {
return "";
}
return await cryptoCreateHash(passwordValue + selectedTargetSiteInfo.siteSalt);
}
function targetPasswordLoadSpecError(errorResponse) {
return { type: TARGET_PASSWORD_LOAD_SPEC_ERROR, errorResponse }
}
function targetPasswordLoadSpecProcess(selectedTargetSiteInfo) {
return (dispatch, getState) => {
let transientPasswordValue = getState().sourcePasswordReducer.transientPasswordValue;
targetPasswordCreatePasswordHash(transientPasswordValue, selectedTargetSiteInfo)
.then(newHashValue => {
let newState = {
selectedTargetSiteInfo: selectedTargetSiteInfo,
targetHashValue: newHashValue
}
dispatch(targetPasswordLoadSpecSuccess(newState))
});
};
}
function targetPasswordLoadSpecStarted() {
return { type: TARGET_PASSWORD_LOAD_SPEC_STARTED }
}
function targetPasswordLoadSpecSuccess(newState) {
return { type: TARGET_PASSWORD_LOAD_SPEC_SUCCESS, newState }
}
--
redux/reducers-targetPassword.js
--
import {
TARGET_PASSWORD_LOAD_SPEC_STARTED,
TARGET_PASSWORD_LOAD_SPEC_SUCCESS,
TARGET_PASSWORD_LOAD_SPEC_ERROR,
} from './actionTypes'
import { commonGetErrorMessage } from './reducers-common'
function targetPasswordAdjustPasswordHash(passwordHash, selectedTargetSiteInfo) {
// make adjustment to password hash, according to rules for target site
return transformedPasswordHash;
}
const targetPasswordInitialState = {
selectedTargetSiteError: '',
selectedTargetSiteInfo: {
siteRules: {
startIndex: 0,
stopIndex: 10,
forceCapitalIndex: 0,
forceNumberIndex: 1,
forceSpecialIndex: 2,
forceSpecialCharacter: '%'
},
siteUserid: ''
},
targetAdjustedHashValue: '',
targetHashValue: '',
targetSaltValue: '',
updateSiteInfo: {
siteRules: {}
}
}
export function targetPasswordReducer(state = targetPasswordInitialState, action) {
let errorMessage = "";
switch (action.type) {
case TARGET_PASSWORD_LOAD_SPEC_ERROR:
errorMessage = commonGetErrorMessage(action.errorResponse);
return {
...state,
selectedTargetSiteError: errorMessage
}
case TARGET_PASSWORD_LOAD_SPEC_STARTED:
return state
case TARGET_PASSWORD_LOAD_SPEC_SUCCESS:
let loadTargetHashValue = action.newState.targetHashValue;
let loadTargetSiteInfo = action.newState.selectedTargetSiteInfo;
let loadAdjustedHashValue = targetPasswordAdjustPasswordHash(loadTargetHashValue, loadTargetSiteInfo);
return {
...state,
selectedTargetSiteInfo: loadTargetSiteInfo,
targetAdjustedHashValue: loadAdjustedHashValue,
targetHashValue: loadTargetHashValue,
targetSaltValue: loadTargetSiteInfo.siteSalt,
updateSiteInfo: loadTargetSiteInfo
}
default:
return state
}
}
--