How to access authData in AWS Amplify Authenticator Component in React Native? - amazon-web-services

I am following the instructions at: https://docs.amplify.aws/ui/auth/authenticator/q/framework/react-native/#using-the-authenticator-component
I can get things working, mostly. I can access authState inside of onStateChange as well, but I cannot figure out how to access authData so I can get things like username, etc.
Could someone please provide an example of how this is done?
Here is my code now:
import { StyleSheet, Text, Button,View,Platform,StatusBar,Image, TouchableWithoutFeedback, SafeAreaView } from 'react-native';
import {useState} from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { useNavigationContainerRef } from '#react-navigation/native';
import Ionicons from 'react-native-vector-icons/Ionicons';
// Screens
import Browsescreen from './screens/Browsescreen';
// AWS
import { Authenticator } from 'aws-amplify-react-native/dist/Auth';
const Tab = createBottomTabNavigator();
function App() {
const navigationRef = useNavigationContainerRef();
const [showLoggedInPage, setLoggedInPage] = useState(false);
const loggedInPage = showLoggedInPage ? (
<SafeAreaView style={styles.container}>
<StatusBar style="auto" />
<View>
[REMOVED]
</View>
<NavigationContainer ref={navigationRef}>
<Tab.Navigator>
[REMOVED]
</Tab.Navigator>
</NavigationContainer>
</SafeAreaView>
) : null;
return (
<Authenticator
onStateChange={(authState) => {
console.log(authState)
if (authState == "signedIn") {
setLoggedInPage(true);
} else {
setLoggedInPage(false);
}
}
}
hideDefault={false}
>
{loggedInPage}
</Authenticator>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ddd',
},
});
export default App;
Please remember I am new so simple answer with sample if possible please. Thank you.

Related

TestingLibraryElementError: Unable to find an element Conditional based data-testid in #testing-library/react

I have written many test cases in the react testing library, I got stuck in the accessing condition based DOM element. I have tried many ways using import { renderHook } from '#testing-library/react-hooks'. But didn't work from me. Here is the code. Great appreciate
import axios from "axios";
import { withTranslation } from "react-i18next";
function MDStaticContent({ t }) {
const [promoArrayIsValid, setPromoArrayIsValid] = useState(false);
const loadRecent = async () => {
API Calls Here
const recents = await onRecentMedia(accounts[0], instance);
if (Some condition) {
if (Here Some condition) {
setPromoArrayIsValid(true);
}
dispatch(Here Will discpatch data);
}
};
return (
<>
{ promoArrayIsValid && (
<div data-testid="mdStaticContent">
Hello
</div>
</>
)}
}
import React from "react";
import { render, cleanup } from "#testing-library/react";
import { useEffect, useState } from "react";
import { Provider } from 'react-redux';
import "#testing-library/jest-dom/extend-expect";
import { MemoryRouter } from 'react-router-dom';
import configureMockStore from 'redux-mock-store';
import { ThemeProvider } from 'styled-components';
import thunk from 'redux-thunk';
import MDStaticContent from "./MDStaticContent";
import { act } from 'react-dom/test-utils';
import MockAPIData from '../resources/locales/en/MockAPIData.json';
import { renderHook } from '#testing-library/react-hooks'
const mockStore = configureMockStore([thunk]);
let data = {
mediaArrayIsValid: true,
promoArrayIsValid: true
}
const store = mockStore(data);
it("should take a snapshot and match of MDStaticContent Page", () => {
const { asFragment, getAllByTestId, getByTestId
} = render(
<ThemeProvider theme={theme}>
<Provider store={store}>
<MemoryRouter>
<MDStaticContent/>
</MemoryRouter>
</Provider>
</ThemeProvider>
);
expect(asFragment()).toMatchSnapshot();
expect(getAllByTestId("mdStaticContent")).toHaveLength(1);
expect(getByTestId("mdStaticContent")).toBeVisible();
});

TypeError: _bundlr_network_client__WEBPACK_IMPORTED_MODULE_0__ is not a constructor while using metaplex.nfts().uploadMetadata()

I'm using this metaplex javascript SDK for working with nfts on solana blockchain.
While uploading the metadata for an nft, I am getting the following error:
TypeError: _bundlr_network_client__WEBPACK_IMPORTED_MODULE_0__ is not a constructor
Code for connecting to metaplex:
const fromWallet = Keypair.generate();
console.log(fromWallet);
const connection = new Connection(clusterApiUrl("devnet"));
const metaplex = Metaplex.make(connection)
.use(keypairIdentity(fromWallet))
.use(
bundlrStorage({
address: "https://devnet.bundlr.network",
providerUrl: "https://api.devnet.solana.com",
timeout: 60000,
})
);
Uploading metadata function:
async function uploadMetadata() {
try {
const { uri, metadata } = await metaplex.nfts().uploadMetadata({
name: formInput.name,
image: image,
description: formInput.description,
});
console.log(metadata.image);
return uri;
} catch (error) {
console.log(`Error uploading metadata - ${error}`);
}
}
I couldn't understand why I'm getting this error. I tried to hit the function by removing .use(keypairIdentity(fromWallet)) from metaplex configuration. But I am getting another error regarding undefined wallet that way. For the similar configuration of metaplex, mx.nfts().findNftByMint(new PublicKey(address)) is working correctly.
Any help is appreciated. Thank you.
I was facing the exact same issue
I opened an issue on metaplex github repo https://github.com/metaplex-foundation/js/issues/138
so it turned out we need to use the wallet adapter
keypairIdentity & walletAdapterIdentity should work on the browser however only walletAdapterIdentity worked for me .
the link to wallet adapter also created by metaplex is https://github.com/solana-labs/wallet-adapter
update, you just need to wrap you app component
import { WalletAdapterNetwork } from '#solana/wallet-adapter-base';
import { ConnectionProvider, useConnection, useWallet, WalletProvider } from '#solana/wallet-adapter-react';
import { WalletModalProvider, WalletMultiButton } from '#solana/wallet-adapter-react-ui';
import {
GlowWalletAdapter,
PhantomWalletAdapter,
SlopeWalletAdapter,
SolflareWalletAdapter,
TorusWalletAdapter,
} from '#solana/wallet-adapter-wallets';
import { clusterApiUrl, PublicKey } from '#solana/web3.js';
import './App.css';
import '#solana/wallet-adapter-react-ui/styles.css';
import { useEffect, useState, useMemo } from "react";
import { Metaplex } from '#metaplex-foundation/js';
export const App = () => {
return (
<BrowserRouter>
<Context>
<Content />
</Context>
</BrowserRouter>
);
};
const Context = ({ children }) => {
const network = WalletAdapterNetwork.Devnet;
const endpoint = useMemo(() => clusterApiUrl(network), [network]);
const wallets = useMemo(
() => [
new PhantomWalletAdapter(),
new GlowWalletAdapter(),
new SlopeWalletAdapter(),
new SolflareWalletAdapter({ network }),
new TorusWalletAdapter(),
],
[network]
);
return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>{children}</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
};
const Content = () => {
const { connection } = useConnection();
const wallet = useWallet();
const metaplex = Metaplex.make(connection);
const [walletAddress, setWalletAddress] = useState('');
const [walletWarning, setWalletWarning] = useState(false);
const [disabled, setDisabled] = useState(false);
useEffect(() => {
const onload = async () => {
await checkIfWalletIsConnected();
}
window.addEventListener('load', onload);
return () => window.removeEventListener('load', onload);
}, []);
return (
<div className='main-app-container'>
<div className='sec-app-container'>
<WalletMultiButton/>
<div className="router-container">
<Routes>
<Route exact path="/" element={<Landing walletWarning={walletWarning} />} />
<Route exact path="/mint_interface"
element={
<MintInterface wallet={wallet} connection={connection} />
} />
</Routes>
</div>
</div>
</div >
);
};
export default App;
and in the MintInterface Component
import { useState } from 'react';
import { Form, Button, Spinner } from 'react-bootstrap';
import { WalletModalProvider, WalletMultiButton } from '#solana/wallet-adapter-react-ui';
import { Metaplex, keypairIdentity, walletAdapterIdentity, bundlrStorage } from '#metaplex-foundation/js';
import { Connection, clusterApiUrl, Keypair } from '#solana/web3.js';
import "./minting.css";
const cluster = "devnet";
function MintInterface({ wallet, connection }) {
const [maturityDate, setMaturityDate] = useState("");
const [quantity, setQuantity] = useState(1);
const [loading, setLoading] = useState(false);
const metaplex = Metaplex.make(connection)
.use(walletAdapterIdentity(wallet))
.use(
bundlrStorage({
address: "https://devnet.bundlr.network",
providerUrl: "https://api.devnet.solana.com",
timeout: 60000,
})
);
);
}
export default MintInterface;
make sure you use walletAdapterIdentity in the configuration

How to hide default SignOut using AWS Amplify with React Native?

I am using AWS Amplify in my React Native app as instructed here: https://docs.amplify.aws/ui/auth/authenticator/q/framework/react-native/#using-the-authenticator-component
It is working, more or less. But when I log in there is a box saying Hello with a Sign Out button added to the project. I can get rid of this by setting hideDefault={true} but then if I log out there is no login/signup screen. My code is below, thank you for any help.
import { StyleSheet, Text, Button,View,Platform,StatusBar,Image, TouchableWithoutFeedback, SafeAreaView } from 'react-native';
import {useState} from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { useNavigationContainerRef } from '#react-navigation/native';
import Ionicons from 'react-native-vector-icons/Ionicons';
// Screens
import Browsescreen from './screens/Browsescreen';
// AWS
import { Authenticator } from 'aws-amplify-react-native/dist/Auth';
const Tab = createBottomTabNavigator();
function App() {
const navigationRef = useNavigationContainerRef();
const [showLoggedInPage, setLoggedInPage] = useState(false);
const loggedInPage = showLoggedInPage ? (
<SafeAreaView style={styles.container}>
<StatusBar style="auto" />
<View>
[REMOVED]
</View>
<NavigationContainer ref={navigationRef}>
<Tab.Navigator>
[REMOVED]
</Tab.Navigator>
</NavigationContainer>
</SafeAreaView>
) : null;
return (
<Authenticator
onStateChange={(authState) => {
console.log(authState)
if (authState == "signedIn") {
setLoggedInPage(true);
} else {
setLoggedInPage(false);
}
}
}
hideDefault={false}
>
{loggedInPage}
</Authenticator>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ddd',
},
});
export default App;
I am new to this, please make it as simple as possible and provide sample if possible. Thank you!
Based on this documentation, if you are using the HOC component withAuthenticator.
export default withAuthenticator(App, {
// Render a sign out button once logged in
includeGreetings: true,
});
The sign-out button is shown when "includeGreetings" is set to "true". Changing it to "false" will hide the sign-out button.

JEST unit testcase - beginner and facing issues

im trying to to convert below code snippet to JEST unit testing but its throwing error please help me out in resolving it
import React from 'react'
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import IdleTimer from 'react-idle-timer';
import { ApolloProvider } from '#apollo/react-hooks';
import Dashboard from '../pages/Dashboard';
import Loader from '../components/Loader';
import Alert from '../components/Alert';
import NoAccess from '../pages/NoAccess';
import { GQL } from '../services/GQL';
import { IdleTimeOutModal } from './IdleTimeoutModal';
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.scss';
import '../assets/css/loader.scss';
import AuthenticatedRoute from '../guards/AuthenticatedRoute';
import auth from '../services/Auth';
import { connect } from 'react-redux';
class Layout extends React.Component {
constructor(props){
super(props);
this.state = {
timeout:1000 * 900 * 1,
showModal: false,
userLoggedIn: window.localStorage.getItem('loginUser'),
isTimedOut: false,
}
this.idleTimer = null
this.onAction = this._onAction.bind(this)
this.onActive = this._onActive.bind(this)
this.onIdle = this._onIdle.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleLogout = this.handleLogout.bind(this)
}
_onAction(e) {
// console.log('user did something', e)
this.setState({isTimedOut: false})
}
_onActive(e) {
// console.log('user is active', e)
this.setState({isTimedOut: false})
}
_onIdle(e) {
// console.log('user is idle', e)
const isTimedOut = this.state.isTimedOut
if (isTimedOut) {
this.setState({showModal: false})
window.localStorage.setItem('loginUser', 'false');
} else {
this.setState({showModal: true})
this.idleTimer.reset();
this.setState({isTimedOut: true})
}
}
handleClose() {
this.setState({showModal: false})
}
handleLogout() {
this.setState({showModal: false})
auth.signout();
}
render(){
// console.log(window.location)
const {match} = window.location.href;
// const { match } = this.location
return(
<>
<IdleTimer
ref={ref => { this.idleTimer = ref }}
element={document}
onActive={this.onActive}
onIdle={this.onIdle}
onAction={this.onAction}
debounce={250}
timeout={this.state.timeout} />
<div className="">
<ApolloProvider client={GQL}>
<Router>
<Switch>
{/* <Route component={NoAccess} path="/no-access" exact={true} /> */}
<AuthenticatedRoute path={`${window.location.pathname}`} component={Dashboard} />
</Switch>
</Router>
{/* <Loader isOpen={loader.isLoading} /> */}
{/* <Alert /> */}
</ApolloProvider>
<IdleTimeOutModal
showModal={this.state.showModal}
handleClose={this.handleClose}
handleLogout={this.handleLogout}
/>
</div>
</>
)
}
}
***JEST throwing error while converting to JEST - ShallowWrapper::state() can only be called on class components
jest help***
export default connect((props) =>({
match: props.uiel.isRequired,
history: props.uiel.isRequired
}))(Layout);
import React from 'react';
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import { render, cleanup, fireEvent } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect';
import Enzyme, { shallow, mount } from 'enzyme';
import Layout from './Layout';
import Adapter from 'enzyme-adapter-react-16';
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import { IdleTimeOutModal } from './IdleTimeoutModal';
import { wrap } from 'module';
Enzyme.configure({ adapter: new Adapter() })
const mockStore = configureMockStore();
let handleLogout:any;
let showModal: any;
let handleClose:any;
let remainingTime:any;
let _onAction:any;
let _onIdle:any;
let _onActive:any;
let idleTimer:any;
describe("Render Layout Component", ()=>{
let store;
let wrapperlayout:any;
beforeEach(()=>{
store = mockStore({
loader: false
});
wrapperlayout = shallow(
<Provider store={store}>
<Layout />
</Provider>
);
});
it('should render the value of color', () => {
wrapperlayout.setProps({ timeout:1000 * 900 * 1 });
wrapperlayout.setProps({ showModal: false });
wrapperlayout.setProps({ userLoggedIn: window.localStorage.getItem('loginUser') });
wrapperlayout.setProps({ isTimedOut: false });
//expect(wrapper.state('color')).toEqual('transparent');
});
it("should increment index - function test", () => {
//const app = shallow(<Normal />);
expect(wrapperlayout.state("isTimedOut")).toEqual('false');
wrapperlayout.instance()._onAction();
expect(wrapperlayout.state("isTimedOut")).toEqual('false');
});
test("Render Modal Layout", ()=>{
expect(wrapperlayout.exists()).toBe(true);
});
});

How to get UserId and set it as a global variable using useContext, useState and useEffect in React-Native?

I have an app built with React-Native, Amplify, AppSync and Cognito and when it loads I would like to save the USER ID and USER TYPE as a global state that can be accessed on every screen.
The user id and user type (Teacher or Student) will never change as these are created on signup.
import React, { useEffect, useState, useReducer } from 'react';
import {AppRegistry} from 'react-native';
import {name as appName} from './app.json';
import App from './src/AppNavigation';
import Amplify, { API, graphqlOperation, Auth } from 'aws-amplify';
import awsmobile from './aws-exports';
import { getUser } from './src/graphql/queries';
Amplify.configure(awsmobile);
export const UserContext = React.createContext()
function MyApp() {
const [userContext, setUserContext] = useState({})
const getUserIdAndType = async () => {
try {
// get User data
const currentUser = await Auth.currentAuthenticatedUser();
const userId = await currentUser.signInUserSession.accessToken.payload.sub;
// get user data from AppSync
const userData = await API.graphql(graphqlOperation(getUser, { id: userId }));
setUserContext({ userId: userId, userType: userData.data.getUser.userType })
} catch (err) {
console.log('error', err);
}
}
useEffect(() => {
getUserIdAndType()
}, [])
return (
<UserContext.Provider value={userContext}>
<App />
</UserContext.Provider>
);
}
AppRegistry.registerComponent(appName, () => MyApp);
Then when I want to use the context state I do as follows:
import { useContext } from 'react';
import { UserContext } from '../../../index';
function Loading ({ navigation }) {
const userContext = useContext(UserContext)
if (userContext.userId != '') {
navigation.navigate('AppTabs');
} else {
navigation.navigate('Auth');
}
}
export default Loading;
Or to get which screen to show (Teacher or Student)...
import { useContext } from 'react';
import { UserContext } from '../../../index';
function LoadingProfile ({ navigation }) {
const userContext = useContext(UserContext)
if (userContext.userType === 'Teacher') {
navigation.navigate('TeacherScreen');
} else if (userContext.userType === 'Student') {
navigation.navigate('StudentScreen');
}
}
export default LoadingProfile;
When the app loads it says the userContext.userId and userContext.userType are empty so it is not saving the state when I set it in the getUserIdAndType() function.
-
****** If I rewrite the App file (INSTEAD OF USING THE HOOKS useState, useEffect) I just declare the values then it works... so I am obviously not using the hooks or async getUserIdAndType() correctly. ******
import React, { useEffect, useState, useReducer } from 'react';
import {AppRegistry} from 'react-native';
import {name as appName} from './app.json';
import App from './src/AppNavigation';
import Amplify, { API, graphqlOperation, Auth } from 'aws-amplify';
import awsmobile from './aws-exports';
import { getUser } from './src/graphql/queries';
Amplify.configure(awsmobile);
export const UserContext = React.createContext()
function MyApp() {
const userContext = {
userId: '123456789', // add the user id
userType: 'Teacher', // add the user type
}
return (
<UserContext.Provider value={userContext}>
<App />
</UserContext.Provider>
);
}
AppRegistry.registerComponent(appName, () => MyApp);
change this :
<UserContext.Provider value={{userContext}}>
<App />
</UserContext.Provider>
to this :
<UserContext.Provider value={userContext}>
<App />
</UserContext.Provider>
you've added an extra curly bracket " { "