Firebase getRedirectResult() doesn't solve - javascript

I am trying to implement the signInWithRedirect() function, but - weirdly enough , it doesn't work. In the below code , Check 2 and Check 3 never get logged - and no error is thrown :
const signInWithGoogle = async () => {
try {
console.log("Check 1")
await signInWithRedirect(auth, googleAuthprovider);
console.log("Check 2")
const result = await getRedirectResult(auth);
console.log("Check 3");
if (result) {
console.log(result.user);
}
} catch (e) {
console.log(e.message.slice(10));
}
};
Also, if I use the exact same Google account to sign in with the signInWithPopup() method, everything works as expected:
const signInWithGoogle = async () => {
const result = await signInWithPopup(auth, googleAuthprovider)
const user = result.user;
console.log(user)
};
I'd really appreciate some help. Thanks!

signInWithRedirect actually navigates away from the page and redirects back to your application so you'll need to handle responses in a separate function that fires when your application loads for the first time.
import {
signInWithRedirect,
getRedirectResult,
GoogleAuthProvider,
} from "firebase/auth"
const googleAuthProvider = new GoogleAuthProvider()
// On Button Click
const signUpGoogle = async () => {
try {
await signInWithRedirect(auth, googleAuthProvider)
} catch (error: any) {
console.log(error)
}
}
// When the page loads
const debugRedirectResult = async () => {
try {
const result = await getRedirectResult(auth)
if (result) {
const details = getAdditionalUserInfo(result)
console.log(details) // details.isNewUser to determine if a new or returning user
} else {
// Everything is fine
}
} catch (error) {
console.log(error) // Debug errors from redirect response
}
}
For example, in React you'd do something like:
// Something like an Auth context provider or App.js
React.useEffect(() => {
const debugRedirectResult = async () => {
try {
const result = await getRedirectResult(auth)
if (result) {
const details = getAdditionalUserInfo(result)
console.log(details) // details.isNewUser to determine if a new or returning user
} else {
// Everything is fine
}
} catch (error) {
console.log(error) // Debug errors from redirect response
}
}
signInWithRedirect()
}, [])
Some things to be aware of:
In certain circumstances getRedirectResult() doesn't throw errors saying an account already exists with another sign in method: https://github.com/firebase/firebase-js-sdk/issues/6051.
These error concerns can be resolved with an email verification flow as explained here: https://firebase.google.com/docs/auth/users#verified_email_addresses

Related

jest timeouts when calling a database query

I have a test file like this.
const { silBastan } = require("../database.js");
const axios = require('axios').default;
describe("authentication", () => {
describe("when data schema is valid", () => {
test("returns 201 response code if the user doesnt already exists", async () => {
await silBastan();
const response = await axios.post('http://localhost:8000/auth/register', {
email: "my_email",
password: "1234"
});
expect(response.status).toBe(201);
});
});
});
And silBastan is defined here like this
const pg = require("pg");
const client = new pg.Client();
async function silBastan() {
return await client.query(`DELETE FROM account`);
}
Of course i made sure the server started and connected to the database before running the tests.
I wondered if there is something wrong with silBastan and tested it inside a express route handler like this
router.post('/register', async (req, res) => {
const { email, password } = req.body;
await silBastan();
try {
await db.createAccount(email, password);
res.sendStatus(201);
} catch (e) {
res.status(400).json({ err: "Already exists" });
}
});
and there was no timeout. And after this i returned another promise from silBastan like this:
async function silBastan() {
// return await client.query(`DELETE FROM account`);
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
And again there is no timeout. I tried couple of other variations as well like these:
function silBastan() {
return client.query(`DELETE FROM account`);
}
async function silBastan() {
await client.query(`DELETE FROM account`);
}
Nothing worked i always get this message:
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
I don't think the problem is with the function because i would get the same behavior in the route handler too.

Function not getting called in useEffect()

I want these two functions to be called every time the component renders, but they are not being executed. And when I put the functions in the dependency array it results in an infinite loop. Any idea why they are not being called?
function PortfolioComponent() {
const [requestedAssets, setRequestedAssets] = useState([]);
const [assets, setAssets] = useState([]);
useEffect(() => {
async function calcValue() {
Promise.all(
requestedAssets.map(async function (asset) {
try {
const response = await axios.get(assetData(asset.AssetId));
let cp = response.data.market_data.current_price.eur;
let value = Number(cp) * Number(asset.Amount);
return { ...asset, value: value, price: cp };
} catch (error) {
console.log(error.response.data.error);
throw error;
}
})
)
.then((newAssetArray) => {
setAssets(newAssetArray);
console.log(newAssetArray);
console.log(assets);
})
.catch((error) => {
console.log(error);
});
}
async function getAssets() {
try {
const response = await axios.get("http://localhost:4200/assets");
// Do as you wish with response here
const assetResponse = response.data.rows;
setRequestedAssets(assetResponse);
console.log(requestedAssets);
} catch (error) {
console.log(error.response.data.error);
}
}
getAssets();
calcValue();
}, []);
Also some weird behaviour I just discovered...
For example, this line of code:
let cp = await response.data.market_data.current_price.eur;
When I remove the await keyword and save it in VS code, the data is retrieved as expected. However, when I refresh the browser the arrays are empty again. The same goes for when I add the await keyword again and save. The same thing happens.
This is what worked for me. So, instead of having a useState variable for requestedAssets, I created a variable inside the getAssets method instead. I'm not exactly sure why this works and not the other way. But, if anybody could explain, that would be great.
function PortfolioComponent() {
//const [requestedAssets, setRequestedAssets] = useState([]);
const [assets, setAssets] = useState([]);
useEffect(() => {
async function getAssets() {
const response = await axios.get("http://localhost:4200/assets");
const requestedAssets = response.data.rows;
console.log(requestedAssets);
Promise.all(
requestedAssets.map(async function (asset) {
try {
const response = await axios.get(assetData(asset.AssetId));
let cp = response.data.market_data.current_price.eur;
let value = Number(cp) * Number(asset.Amount);
return { ...asset, value: value, price: cp };
} catch (error) {
console.log(error.response.data.error);
throw error;
}
})
)
.then((newAssetArray) => {
setAssets(newAssetArray);
console.log(newAssetArray);
console.log(assets);
})
.catch((error) => {
console.log(error);
});
}
getAssets();
}, []);
The recommendation is to declare your functions inside the useEffect, see the official documentation. If you keep scrolling in the docs, they even have an example similar to yours, with an async function.
If, for some reason, you do need to have your function declared outside the useEffect, you can use a useCallback, which allows you to declare them in the dependency array. Something like this:
const getAssets = useCallback(async() => {
try {
const response = await axios.get("http://localhost:4200/assets");
// Do as you wish with response here
const assetResponse = response.data.rows;
setRequestedAssets(assetResponse);
console.log(requestedAssets);
} catch (error) {
console.log(error.response.data.error);
}
}, [requestedAssets])
useEffect(() => {
getAssets()
}, [getAssets])
You can also see the section Do I need to specify functions as effect dependencies or not? in this blog here for more information.
PS: This blog is from Dan Abramov, one of the creators of React, so reliable source ;)

Handle promises inside redux actions with thunk

I have a fake login function like this
const login = (email, password) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (email === "demo#gmail.com" && password === "demo1234") {
resolve(200);
} else {
reject(401);
}
}, 1000);
});
};
This is my authAction.js file
export const login = (email,password) => async(dispatch) => {
try {
await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
} catch (error) {
console.log(error)
}
}
In my LoginPage.js react component I call the action like this
const submit = ({ email, password }) => {
props.login(email, password).then((e) => console.log("then",e)).catch(err=>console.log("ca"));
};
If I pass the wrong credentials it logs the error code 401 inside the action. But in the LoginPage component, it always comes to the then block and prints undefined.
Even if I pass the right credentials it comes to then block and prints 'undefined'
But If I modify the action to return 200 or the error
export const login = (email,password) => async(dispatch) => {
try {
await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
return 200
} catch (error) {
return error;
}
}
Now it prints the error code in "then" block of the LoginPage component.
Simply I want to inform the LoginPage component of what happened to the request. So what I am doing right now is okay or is there any other performance optimal way to do this?
Any help
Thanks in advance!
You forgot return value in then and throw error in catch
export const login = (email,password) => async(dispatch) => {
try {
const res = await fakeLogin(email,password)
dispatch({
type:LOGIN,
payload:{}
})
return res
} catch (error) {
console.log(error)
throw error
}
}

how to solve console log issue in chrome browser

I'm getting data from an API and initially when console it in fetchData function it works but when console it in fetchDailyData function and call this function in another component it didn't work.
How can I solve this issue?
import axios from 'axios';
const url = `https://covid19.mathdro.id/api`;
export const fetchData = async () => {
try {
const { data: { confirmed, recovered, deaths, lastUpdate }} = await axios.get(url);
return { confirmed, recovered, deaths, lastUpdate };
} catch (error) {
}
}
export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/daily`);
console.log(data); // <<==>> chrome browser is not showing this console log
// fetchDailyData function called in another component
} catch (error) {
}
}
Calling fetchDailyData function in another component
when I call console.log, I can't see the data in console of my browser
const Chart = () => {
const [dailyData, setDailyData] = useState({});
useEffect(() => {
const fetchApi = async () => {
setDailyData(await fetchDailyData());
}
console.log(dailyData);
fetchApi();
});
};
https://covid19.mathdro.id/api/daily which is your url in fetchDailyData doesn't return any data currently at all.
I suppose you have to check if this backend still available. And it is a good practice to check the response status (normally it should return statusCode 200) in response callback.

memory leak error when redirect to home if user is not logged in

I've trying to redirect to home if user is not logged in(status 401) in componentDidMount.
So I tried
componentDidMount() {
const requestPatientListApi = async () => {
try {
const { data } = await get<AxiosResponse<PatientApi>>("/patient", { requester: "admin" });
return data.items;
} catch (err) {
//when user is not logged in redirect to "./"
props.history.push("./");
}
return [];
};
if (!axios.isCancel("")) {
// updating state when api call is not canceled
requestPatientListApi().then(patients => {
setPatients(patients);
});
}
}
componentWillUnmount() {
if (cancel) {
cancel();
}
}
But, the error occurs:
Warning: Can't perform a React state update on an unmounted component.
I've tried using axios cancel token, but it seems not a solution for this case.
Any ideas?
The issue is that you're redirecting before setting a state, in which case the component is not rendered anymore. One way would be to forward the error in your async func and catch it later.
componentDidMount() {
const requestPatientListApi = async () => {
try {
const { data } = await get <AxiosResponse<PatientApi>>("/patient", {
requester: "admin"
});
return data.items;
} catch (err) {
throw err; // Forward the error further
}
return [];
};
if (!axios.isCancel("")) {
requestPatientListApi().then(patients => {
setPatients(patients);
}).catch(err => {
props.history.push("/"); // handle the error here
});
}
}

Categories