Ionic-React Accessing Local Storage For Mobile - javascript

I am trying to create a login simple login system using ionic and a database. I'm using a simple SQL Query to make sure the login credentials are valid, and then shoot the user over to the main dashboard page. I am trying to display the name of the user with a header 'Welcome '.
I am using Ionic with react.js. I am also using Capacitor. Whenever I test the app on my laptop as a web app, works like intended and shows the user's name. As soon as I test if via my android device, it logs me in correctly but does not show the user's name. What could I be missing?
For debugging purposes I changed it from the name to the id number of the user... still not properly displaying the number tho...
Web app - This is what the mobile is supposed to look like but isn't
Login Code
import React, { useState, useEffect } from 'react';
import { Plugins } from '#capacitor/core';
import './Login.css';
import { Link, Redirect } from 'react-router-dom';
import axios from 'axios';
const { Storage } = Plugins;
const Login: React.FC = () => {
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const [isError, setIsError] = useState<boolean>(false);
function handleLogin() {
// // const baseURL = process.env.NODE_ENV !== "production" ? "http://localhost:3000" : "https://freightsnap-proto.herokuapp.com"
const baseURL = "https://freightsnap-proto.herokuapp.com";
console.log("user: " + username);
console.log("pass: " + password);
let userInfo = {
username: username,
password: password
}
axios.post(baseURL + "/login", userInfo) .then(function(response) {
if(response.data.length != 0) {
setIsError(false);
let userInfo = response.data[0];
let data = JSON.stringify(userInfo);
setUserData(data, userInfo.id);
}
else {
console.log("err");
setIsError(true);
}
});
}
async function setUserData(data: any, id: any){
await Storage.set({
key: 'user',
value: data,
});
await Storage.set({
key: '_id',
value: id,
});
window.location.href = "/home"
// getUserData();
}
async function getUserData() {
// const { value } = await Storage.get({ key: 'user' });
// console.log("getting...");
// const user = console.log(value);
// const ret = await Storage.get({ key: '_id' });
// const user = JSON.parse(ret.value || '{}');
// console.log(user);
}
return (
<IonPage>
<IonContent>
<div className="bg-light">
<h1 className="header">[LOGO]</h1>
<div className="container">
<IonInput style={{ paddingTop: "30px" }} placeholder="Username" className="dark-txtbox" value={username} onIonChange={(e: any) => setUsername(e.target.value)} ></IonInput>
<IonInput placeholder="Password" type="password" className="dark-txtbox" value={password} onIonChange={(e: any) => setPassword(e.target.value)} ></IonInput>
<IonButton onClick={handleLogin} className="btn-mainBlue" shape="round" expand="full">Login</IonButton>
{
isError ? (
<p style={{color: "red"}}>Invalid Login!</p>
) : (
<p></p>
)
}
</div>
</div>
</IonContent>
</IonPage>
);
};
export default Login;
Dashboard Code
import React, { useState, useEffect } from 'react';
import ExploreContainer from '../components/ExploreContainer';
import { Plugins } from '#capacitor/core';
import './Home.css';
import axios from 'axios';
const { Storage } = Plugins;
const Home: React.FC = () => {
const [userFullName, setUserFullName] = useState<string>('');
useEffect(() => {
getUserData();
// const baseURL = process.env.NODE_ENV !== "production" ? "http://localhost:3000" : "https://freightsnap-proto.herokuapp.com"
// var url = window.location.href;
// var splitUrl = url.split("/");
// var userId = splitUrl[4]
// console.log(userId);
// axios.get(baseURL + `/findUser/${userId}`).then(response => {
// setUserFullName(response.data[0].user_name);
// console.log(userFullName);
// })
})
async function getUserData() {
const { value } = await Storage.get({ key: '_id' });
// const baseURL = process.env.NODE_ENV !== "production" ? "http://localhost:3000" : "https://freightsnap-proto.herokuapp.com"
const baseURL = "https://freightsnap-proto.herokuapp.com";
console.log(value);
setUserFullName(value || "");
// axios.get(baseURL + `/findUser/${value}`).then(response => {
// setUserFullName(response.data[0].user_name);
// console.log(userFullName);
// })
}
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Dashboard - Welcome {userFullName}</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Blank</IonTitle>
</IonToolbar>
</IonHeader>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
export default Home;

Based on your code, I think your async function getUserData in Dashboard code is still retrieving the data from your server, so the data is not available yet to show. A suggested change that might work will be
useEffect(() => {
getUserData();
}, [userFullName]);
This will update userFullName when there is a change in that variable and should update the view with the name of the user.

Related

How to log into a user account page upon storing login data in session storage?

I am building a simple login system in React and I am attempting to allow a user to input an email and password to log in, only after this log in data is saved to session storage. The email and password are successfully stored in session storage, but the page does not refresh & subsequent return {} function in my-account.js does not render.
My understanding of how this code works:
the 'useToken()' hook contains a state object with the function 'getToken()' and the state variable 'token', with a state determined by 'useState(getToken())' - which will set the state of 'token' to the session storage variable named 'token'.
useToken() is imported into my-account.js and 'token' and 'setToken()' are both destructured from the parent function, retrieving the correct data in the my-account component.
The 'useToken()' function does not set 'token' and it returns a null, when it should be returning the token that is successfully stored in session storage. I would appreciate any help with this one.
//my-account.js
import React from 'react';
import Login from "../components/login"
import useToken from "../hooks/useToken"
const MyAccount = () =>{
const { token, setToken } = useToken();
if(!token) {
return <Login setToken={setToken} />
}
return (
<div>
<div>
<h1>{token.email ? `Logged in as ${token.email}` : 'Not logged in'}</h1>
</div>
</div>
);
}
export default MyAccount;
//useToken.js
import { useState } from 'react';
export default function useToken() {
const getToken = () => {
const tokenString = localStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken;
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken) => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken);
};
return {
setToken: saveToken,
token,
}
}
//login.js
const Login = ({setToken}) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isLoggingIn, setIsLoggingIn] = useState(false);
const [error, setError] = useState(null);
Login.propTypes = {
setToken: PropTypes.func.isRequired
}
const handleSubmit = async (event) => {
event.preventDefault();
setIsLoggingIn(true);
try {
const { data } = await axios.get("http://localhost:3001/users", { email, password });
console.log(data);
const user = data.find(
(user) => user.email === email && user.password === password
);
if (user) {
console.log("user is found");
// set token to store pass as a prop to store login data in local memory
var token = user;
console.log(token);
setToken(token);
setError(false);
setIsLoggingIn(false);
} else {
setError(new Error("Incorrect email or password"));
setIsLoggingIn(false);
}
} catch (error) {
setError(error);
setIsLoggingIn(false);
}
};
return (
<form onSubmit={handleSubmit} className="login-container">
{error && <div className="error">{error.message}</div>}
<label htmlFor="email">Email:</label>
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<br />
<label htmlFor="password">Password:</label>
<input
type="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
<br />
<>
<button className="fancyButton defaultBtn" type="submit" disabled={isLoggingIn}>
{isLoggingIn ? 'Logging in...' : 'Log In'}
</button>
</>
<p>If you do not have an account, register <Link to="/register">here</Link></p>
</form>
);
}
export default Login;
The problem must be in <Login>
I made a local copy and it worked just fine. Here is my Login.js
function Login({ setToken }) {
setToken("test");
return <div></div>;
}
export default Login;

Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. - useEffect()

I get this error when I try and call a function I have imported within my useEffect() hook in Dashboard.jsx. I am just trying to pull in data from database on the page load pretty much so that when user click button they can send off correct credentials to the api.
I am pulling it in from database for security reasons, so client id is not baked into the code.
I am pretty sure that I am getting this error maybe because the function is not inside a react component? although I am not 100% sure. And if that is the case I am not sure of the best way to restructure my code and get the desired output.
Code below.
mavenlinkCredentials.js
import { doc, getDoc } from "firebase/firestore";
import { useContext } from "react";
import { AppContext } from "../../context/context";
import { db } from "../../firebase";
const GetMavenlinkClientId = async () => {
const {setMavenlinkClientId} = useContext(AppContext)
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
export default GetMavenlinkClientId;
Dashboard.jsx
import React, { useContext, useEffect, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useNavigate } from "react-router-dom";
import { query, collection, getDocs, where, setDoc, doc, getDoc } from "firebase/firestore";
import { auth, db, logout } from "../firebase";
import { Button, Container, Grid, Paper } from "#mui/material";
import ListDividers from "../components/ListDividers";
import { AppContext } from "../context/context";
import axios from "axios";
import {SuccessSnackbar, ErrorSnackbar} from '../components/PopupSnackbar';
import GetMavenlinkClientId from "../helpers/firebase/mavenlinkCredentials";
const Dashboard = () => {
const [user, loading, error] = useAuthState(auth);
const [name, setName] = useState("");
const [ accessToken, setAccessToken ] = useState("")
const [errorAlert, setErrorAlert] = useState(false);
const [successAlert, setSuccessAlert] = useState(false);
const [mavenlinkClientId, setMavenlinkClientId] = useState("");
const {isAuthenticated} = useContext(AppContext);
const navigate = useNavigate();
const uid = user.uid
const parsedUrl = new URL(window.location.href)
const userTokenCode = parsedUrl.searchParams.get("code");
const { mavenlinkConnected, setMavenlinkConnected } = useContext(AppContext)
const { maconomyConnected, setMaconomyConnected } = useContext(AppContext)
const { bambooConnected, setBambooConnected } = useContext(AppContext)
const fetchUserName = async () => {
try {
const q = query(collection(db, "users"), where("uid", "==", user?.uid));
const doc = await getDocs(q);
const data = doc.docs[0].data();
setName(data.name);
} catch (err) {
console.error(err);
alert("An error occured while fetching user data");
}
};
//
useEffect(() => {
if (loading) return;
if (!user) return navigate("/");
fetchUserName();
if(userTokenCode !== null){
authorizeMavenlink();
}
if(isAuthenticated){
GetMavenlinkClientId()
}
}, [user, loading]);
///put this into a page load (use effect maybe) so user does not need to press button to connect to apis
const authorizeMavenlink = () => {
console.log(uid);
const userRef = doc(db, 'users', uid);
axios({
//swap out localhost and store in variable like apitool
method: 'post',
url: 'http://localhost:5000/oauth/mavenlink?code='+userTokenCode,
data: {}
})
.then((response) => {
setAccessToken(response.data);
setDoc(userRef, { mavenlinkAccessToken: response.data}, { merge: true });
setMavenlinkConnected(true);
setSuccessAlert(true);
})
.catch((error) => {
console.log(error);
setErrorAlert(true)
});
}
//abstract out client id and pull in from db
const getMavenlinkAuthorization = () => {
window.open('https://app.mavenlink.com/oauth/authorize?client_id='+mavenlinkClientId+'&response_type=code&redirect_uri=http://localhost:3000');
window.close();
}
const authorizeBamboo = () => {
axios({
method: 'get',
url: 'http://localhost:5000/oauth/bamboo',
data: {}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error);
});
// console.log('bamboo connected')
setBambooConnected(true);
}
const authorizeMaconomy = () => {
console.log("Maconomy connected")
setMaconomyConnected(true);
}
const syncAccount = async() => {
if(!mavenlinkConnected){
await getMavenlinkAuthorization()
}
if (!bambooConnected){
await authorizeBamboo();
}
if (!maconomyConnected){
await authorizeMaconomy();
}
}
const handleAlertClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSuccessAlert(false) && setErrorAlert(false);
};
console.log(mavenlinkClientId);
return(
<>
<Container>
<div className="dashboard">
<h1>Dashboard</h1>
<Grid container spacing={2}>
<Grid item xs={12}>
<Paper style={{paddingLeft: "120px", paddingRight: "120px"}} elevation={1}>
<div className="dashboard-welcome">
<h2>Welcome {name}</h2>
<h4>{user?.email}</h4>
<hr/>
<h2>Integrations</h2>
<Button onClick={syncAccount}>
Sync Account
</Button>
{/* <Button onClick={getMavenlinkClientId}>
Bamboo Test
</Button> */}
<ListDividers/>
</div>
</Paper>
</Grid>
</Grid>
</div>
{successAlert === true ? <SuccessSnackbar open={successAlert} handleClose={handleAlertClose}/> : <></> }
{errorAlert === true ? <ErrorSnackbar open={errorAlert} handleClose={handleAlertClose}/> : <></> }
</Container>
</>
);
}
export default Dashboard;
the error is because you’re calling const {setMavenlinkClientId} = useContext(AppContext) inside the file mavenlinkCredentials.js which is not a react components.
you could maybe change the function inside mavenlinkCredentials.js to accept a setMavenlinkClientId and pass it from outside like this.
const GetMavenlinkClientId = async (setMavenlinkClientId) => {
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
and then you can call this function in your dashboard.js like so,
const {setMavenlinkClientId} = useContext(AppContext)
if(isAuthenticated){
GetMavenlinkClientId(setMavenlinkClientId)
}

How to retrieve data from a Firestore database

I am doing a project in React, where after I type a value and then click on search button, the app searches if the id exists in the database. If so, it displays the result of the search in the same page. I am having trouble assigning the value of the search and then displaying it. When I try to assign the result of the search to an array, it gives me the error:
Type 'DocumentData[]' is not assignable to type 'Dispatch<SetStateAction<Identification[]>>'.
Type 'DocumentData[]' provides no match for the signature '(value:SetStateAction<Identification[]>): void'.
When I did a console.log of just the data in no variable, I can get the results, but I need it in the setId variable.
Here is the code:
import React, {ChangeEvent} from "react";
import { useState,useEffect } from "react";
import LongText from "../atoms/LongText";
import AppListBI from "./AppListBI";
import {Identification} from "../../assets/Person/Person";
import db from "../../firebase.config"
const Core = () => {
var [input, setInput] = useState('')
const [showResults, setShowResults] = React.useState(false)
var [person, setId] = useState<Identification[]>([]);
const fetchBI = async () => {
const ref=db.collection('id').where('numberId','==',input).get().then((snapshot) => {
snapshot.docs.forEach(doc =>{
setId=[...person,doc.data()]
//I also tried
setId=doc.data()
})
})
}
return (
<>
<div className="mx-7">
<span className="font-bold text-xl"><h5>Pesquisar:</h5></span></div>
<div className="flex justify-center">
<LongText placeholder="Pesquisar Id" onChange={
(e: ChangeEvent<HTMLInputElement>)=>setInput(e.target.value)}
onClick={useEffect(()=>{
setShowResults(true)
fetchBI();
})}/>
</div>
<div className="flex justify-center">
<span className="my-4 w-11/12">
{ showResults ? <AppListId persons={person} /> : null }
</span>
</div>
</>
);
}
export default Core;
After long days I found the solution:
I traded this:
const fetchBI = async () => {
const ref=db.collection('id').where('numberId','==',input).get().then((snapshot) => {
snapshot.docs.forEach(doc =>{
setId=[...person,doc.data()]
to:
const fetchBI = async () => {
try{
var people : ID[] = []
await db.collection('id').where('numberId','==',input).get().then(
querySnapshot=>{
const data = querySnapshot.docs.map(
doc=>{
let dat = doc.data()
people.push({
numberId: dat.numberId,
name: dat.name,
dateOfBirth: dat.dateOfBirth,
placeOfBirth: dat.placeOfBirth,
fathersName: dat.fathersName,
mothersName: dat.mothersName,
gender: dat.gender,
profession: dat.profession,
dateOfIssue: dat.dateOfIssue,
expirationDate: dat.expirationDate
})
})
setId(people)
}
)
}catch (error) {
console.log(error.message)
}
}

React Native logout functionality not working properly

Hy, I'm creating the react-native app in native-cli. I'm trying first-time navigation 5. when I do the login I receive the Token and store it in AsyncStorage but need to reload the app to move toward the dashboard so to solve this I used the useContext and its working fine but now the issue is that when I login the app and move around it and then press the logout button it works nicely but when I login the app surf the app and then press the back button go to the home screen of mobile without logout then again when I come back to the app and press log out it clear the AsyncStorge but not log out the app and I need to refresh then it goes back to the login screen.
App.js
const App = () => {
const [user, setUser] = useState(false)
const [log, setLog] = useState(0)
const [role, setRole] = useState('seller')
//console.log('App.js-Start')
console.log("app_User:",user);
console.log("app_log:",log);
useEffect(()=>{
getKeysData(dataKeys)
},[])
const dataKeys = ['token', 'super_user_status', 'isLoggedIn'];
const getKeysData = async (keys) => {
const stores = await AsyncStorage.multiGet(keys);
//console.log(stores)
// const aData = stores.map(([key, value]) => ({ [key]: value }))
const aData = await Promise.all(stores.map(([key, value]) => ({[key]: value})))
const token = aData[0]['token']
const super_user_status = aData[1]['super_user_status']
const isLoggedIn = aData[2]['isLoggedIn']
console.log('token',token)
console.log('SuperUser', super_user_status)
console.log('Log',isLoggedIn)
//setUser(isLoggedIn)
if(isLoggedIn == 1){
setLog(1)
}
}
return (
<NavigationContainer>
<LoginContext.Provider value={{user,setUser}} >
{ user == false && log==0 ?
<AuthStackScreen />
:
<BuyerDashboardStackScreens />
}
</LoginContext.Provider>
</NavigationContainer>
);
};
export default App;
Login
await axios({
method: 'POST',
url: api + 'login/',
data: login_Credentials,
headers: { 'Content-Type': 'multipart/form-data' }
}).then(async function (response) {
if (response.data.success == true) {
const token = response.data.token.toString();
const super_user_status = response.data.super_user_status.toString();
const isLoggedIn = "1"
//console.log('Logged In and set Storgae')
await AsyncStorage.multiSet([['isLoggedIn',isLoggedIn],['token', token], ['super_user_status', super_user_status]])
setUser(true)
setEmail('')
setPassword('')
setPress(false)
}
logout
const logOut = () => {
AsyncStorage.clear();
setUser(false);
};

Why does the user getting redirected to the login page on refresh?

Okay, there's this simple REACTJS app, where firebase is used.
There once you login everything works fine except when you hit the refresh icon. The moment you do it, it redirects you to the previous place where you were asked to login. That's the problem that this newly-born coder is trying to solve!
I can give you following snippets of code:
This is of the landing page
function Landing() {
const [{ }, dispatch] = useStateValue();
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE)
// .then(function () {
// console.log("successfully set the persistence");
// return firebase.auth().signInWithPopup(provider);
// })
.catch(function (error) {
console.log("failed to ser persistence: " + error.message)
});
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user is logged in');
} else {
console.log('user is logged out now')
}
});
const signIn = () => {
auth
.signInWithPopup(provider)
.then((result) => {
dispatch({
type: actionTypes.SET_USER,
user: result.user
})
}).catch((error) => alert(error.message))
}
reducer.js snippet
export const initialState = {
user: null,
}
export const actionTypes = {
SET_USER: 'SET_USER',
LOGOUT_USER: 'LOGOUT_USER'
}
const reducer = (state, action) => {
console.log(action)
switch (action.type) {
case actionTypes.SET_USER:
return {
...state,
user: action.user,
}
case actionTypes.LOGOUT_USER:
return {
...state,
user: null,
}
default:
return state;
This is of firebase.js
Yes, Google Authentication is what's being used here
import firebase from 'firebase';
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
//config
};
// const user = firebase.auth().currentUser;
// console.log(user);
const firebaseApp = firebase.initializeApp(firebaseConfig)
const db = firebaseApp.firestore();
const storage = firebase.storage();
const auth = firebaseApp.auth();
const provider = new firebase.auth.GoogleAuthProvider();
export default db;
export { auth, provider, storage }
Finally here is of the app.js
function App() {
const [{ user }, dispatch] = useStateValue();
console.log(user);
return (
<div className="app">
{!user ? (
<Landing />
) : (
<App />
)
</div>
Your attention to this matter is greatly appreciated!
Oh by the way this following question is also related to this. It might help you to get a better idea of this issue. So make sure to take a look at that as well!
How can you persist a logged-in user with firebase?
Thanks again!
sample code. work
import firebase from 'firebase/app';
import 'firebase/auth';
import { useEffect, useState } from 'react';
import firebaseConfig from './firebase-config';
const firebaseApp = firebase.initializeApp(firebaseConfig);
const googleProvider = new firebase.auth.GoogleAuthProvider();
firebaseApp.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(function () {
// return firebaseApp.auth().signInWithPopup(googleProvider)
})
.catch(function (error) {
console.log(error)
});
function App() {
const [user, setUser] = useState(null)
useEffect(() => {
firebaseApp.auth().onAuthStateChanged((res) => {
console.log("onAuthStateChanged", res)
if (res) {
setUser(res)
// console.log('user is logged in', user);
} else {
setUser(null)
// console.log('user is logged out now')
}
});
}, [])
const signInWithGoogle = (e) => {
firebaseApp.auth()
.signInWithPopup(googleProvider)
.then((result) => {
// console.log(result)
// setUser(result.additionalUserInfo)
}).catch(err => {
// console.log(err)
})
}
const signOut = (e) => {
firebaseApp.auth().signOut()
}
return (
<div>
<h1>Firebase Authentication</h1>
{
user
? (
<div>
<p>Hello, {user.displayName}</p>
<button onClick={signOut}>Sign out</button>
</div>
)
: (
<div>
<p>Please sign in.</p>
<button onClick={signInWithGoogle}>Sign in with Google</button>
</div>
)
}
</div>
);
}
export default App;

Categories

Resources