Can't fetch right data on the button click from fireStore - reactjs

I am doing my first bigger react project, where I am biulding web app for barbershop.
Idea is this. When I want to make reservation, I need to choose service type (regular haircut, beard trim or both) and then I need to choose barber. Depending which barber I choosed I fetch data from firestore. Barbers name is actually firebase collection name of the barber where is his schedule when there is free apointment.
Problem is this. When I choose service and then choose barber John, nothing happens, but if I then click on barber Carl I get John's schedule.
In the picture there is my component and how it is set up.
Here is the code of my function which is not working right.
I tried many things, it is not working even with timeOut.
useEffect(() => {
if (!service || !barber) {
return;
}
if (fetching) {
setTimeout(async () => {
try {
const barbers_name = barber;
const freeTimeRef = collection(db, `${barbers_name}`);
const q = query(freeTimeRef);
const querySnap = await getDocs(q);
let freeTimeArr = [];
querySnap.forEach((doc) => {
freeTimeArr.push(doc.data().radno_vrijeme);
return freeTimeArr;
});
setSchedule(freeTimeArr);
} catch (error) {
toast.error(error);
} finally {
setLoading(false);
setFetching(false);
}
}, 100); // delay the call by 100 milliseconds
}
}, [fetching, barber]);
setFetching is being used in this function, and this function changes state of the button from the picture, to the barbers name or service type.
const HandleChangeBarber = (e) => {
setBarber(e.currentTarget.textContent);
setFetching(true);
};

Related

Firebase Storage async request with "listAll" method. React

I'm getting an image from a user and storing it with in Cloud Storage through Firebase. The storing works fine.
Right after that I'm requesting all images from the storage to display them, but I got the response without the last submit. So I need to refresh the page, then useEffect make one more request and everything works.
UPD. Here's the the complete logic:
This function is uploading image to the storage:
const uploadImage = async (image,imageName) => {
if (image == null) return;
const imageRef = ref(storage,`images/${imageName}`);
try {
uploadBytes(imageRef, image);
} catch (err) {
alert(`${err}`)
}
}
This function does request to firestore, but doesn't return last uploaded image every time, just randomly. sometimes it does, usually not :
const getImages = async () => {
try {
const imagesListData = await listAll(imagesListRef);
setImagesList([]);
imagesListData.items.forEach(item => {
getDownloadURL(item).then(url => setImagesList(prev => [...prev,url]));
})
} catch(err){
alert(err.message);
}
}
after refreshing the page, useEffect does the job :
useEffect(() => {
getImages();
},[])
As I said above sometimes it works as I expected from the first try without me changing the code(which is the most confusing),most of the times I need to refresh the page to get the last image.
p.s. list() instead listAll() give same results

Update state in react - big change in DOM works with delay

I render in my app transcription lines, 100 on average.
There is an option to translate the transcription lines.
Clinking a button toggles between show translation and not showing translation.
When I click on it, there is a delay of 1-2 seconds that the site gets stuck, then the change happens...
Anyone knows a better way to update a big change of state in react (with mobx)?
Somehow I managed to control the stuckness with setTimeout, but I don't believe this is the way...
Thanks!
const updateStateWithTimeout = async (time: number, requestForTranscript?: boolean) => {
requestForTranscript && await getTranscriptionsTranslations(sessionId!);
setTimeout(async () => {
requestForTranscript && await loadCallLogDataForTranslation(sessionId!);
setShowTranslation(!showTranslations);
setIsLoadingTranslations(false);
}, time)}
const handleTranslateButton = async () => {
setIsLoadingTranslations(true);
if (language?.includes("en")) {
ToastUtil.error("The language of the call is English");
return;
}
if (online) await showTranslationOnlineCall();
else {
if (hasTranslations) await updateStateWithTimeout(1000);
else await updateStateWithTimeout(3000, true);
}
}

Cannot get channels moving event in Discord audit log

I'm trying to log the Discord event when someone is moving any channel.
The channelUpdate event works almost like a charm and returning 2 events (two, because of when you moving one channel the rawPosition property is changing in the target's channel and in the channel you swiped the place). Except strange cases when you moved one channel and getting tone of events as if you moved all the server channels at ones. Weird thing, yep.
The problem is the "channelUpdate" event returns only oldChannel and newChannel but not the executor data (who and when).
I've tried to use guild.fetchAuditLogs({ type: 14, limit: 1 }) but looks like it's not returning changing position events. One gets the feeling Discord's log engine is not logging this event OR I'm looking in wrong place. Also tried type 11 and even NULL with no luck on finding rawPosition prop changing.
Please, help me to find the way how to log WHO is changing the channels position or tell me it's not possible at the time.
Some code here:
const Discord = require('discord.js');
const client = new Discord.Client({ shards: 'auto'});
const { prefix, token, witaitoken , guildID, DBUser, DBPass } = require('./config.json');
client.on('ready', async () => {
console.log(`Logged in as ${client.user.tag}!`);
client.user.setActivity(`Star Citizen`, { type: 'PLAYING' });
});
client.on('channelUpdate', (oldChannel, newChannel) => {
if (oldChannel.rawPosition !== newChannel.rawPosition) {
oldChannel.guild.fetchAuditLogs({ limit: 10 })
.then( (audit) => {
const log = audit.entries;
if (!log) return;
fs = require('fs');
fs.appendFile('audit.txt', JSON.stringify(log), function (err) {
if (err) return console.log(err);
});
})
}
});
client.login(token);
client.on("error", (e) => console.error(e));
client.on("warn", (e) => console.warn(e));
client.on("debug", (e) => console.info(e));

reCAPTCHA first attempt causes it to reset. Firebase phoneAuthVerifier

Hello I'm having issues implementing recaptcha into our firebase project. I'm using it with firebase.auth.PhoneAuthProvider, to initially enroll a second factor and then use the recaptcha for multi-factor authentication on login.
I've used the https://cloud.google.com/identity-platform/docs/web/mfa doc for the implementation and it does work but it resets on the first successful attempt. The tickbox gets checked but instantly the whole recaptcha rerenders/is reset.
https://imgur.com/PJCJujo (here is a tiny video of that reset behaviour)
The fact that it is rerendering makes me think it is an error in the implementation and possibly to do with React but I am struggling to solve it.
Login Function
const frontendLogin = () => {
const { email, password } = registerDetails
firebaseApp.auth().signInWithEmailAndPassword(email, password)
.then(data => {
// if (data.user.emailVerified) {
axios.get(`/users/${data.user.uid}`)
.then(res => {
// Handle login for users not enrolled with multi-factor
})
.catch(error => {
console.log(error)
if (error.code === 'auth/multi-factor-auth-required') {
setResolver(error.resolver)
setHints(error.resolver.hints[0])
setPhoneVerifyRequired(true)
// Ask user which second factor to use.
if (error.resolver.hints[selectedIndex].factorId ===
firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
const phoneInfoOptions = {
multiFactorHint: error.resolver.hints[selectedIndex],
session: error.resolver.session
};
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider(appAuth);
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
captchaRef.current,
{
'size': 'normal',
'callback': function (response) {
console.log('captcha!')
handleSolved()
},
'expired-callback': function () {
console.log('captcha expired')
},
'hl': locale
},
firebaseApp);
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function (verificationId) {
setVerificationId(verificationId)
}).catch(err => console.log(err))
} else {
// Unsupported second factor.
}
} else {
console.log(error)
}
})
}
const handleSolved = () => {
setCaptchad(true)
setIsLoading(false)
}
const handleRecaptcha = () => {
var cred = firebase.auth.PhoneAuthProvider.credential(
verificationId, verificationCode);
console.log(cred)
var multiFactorAssertion =
firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
resolver.resolveSignIn(multiFactorAssertion)
.then(function (data) {
// User successfully signed in with the second factor phone number.
// Handle login for users enrolled with multi-factor
})
}
I am unsure as to why this approach isn't working but I believe it may be to do with React? I have looked into using a React Recaptcha package but as the docs were just written in javascript I've just tried to implement it in this way.
I haven't deviated too far from the docs only to set state with elements including the verification ID that is returned from the successful recaptcha etc.
I also appreciate I am setting state too much and need to refactor the state at the top of the component but as I'm still fleshing this component out it hasn't been refactored yet so I apologise it's a bit messy!
If anyone has any pointers that would be great or if I need to provide more code then let me know, any help is appreciated!

React keep old state - new state not updated

In a React project, I have a state gameResults with a array of games, and I have a function to get the list of games based on a query :
useEffect(() => {
const timeoutId = setTimeout(() => {
if (gameQuery.length > 0) {
axios.get(`/api/games/${gameQuery}`).then((response) => {
const igdbGames: IGDBGame[] = response.data.games;
const formatedGames = formatGames(igdbGames);
setGameResults(formatedGames);
});
}
}, 300);
return () => clearTimeout(timeoutId);
}, [gameQuery]);
For each game, I don't have the cover, so I get the cover for each game :
const loadGamesImages = async () => {
for (let i = 0; i < gameResults.length; i++) {
axios
.get(`/api/cover/${gameResults[i].id}`)
.then((response) => {
const coverUrl: IGDBCover = response.data.covers[0];
const newGame = {
...gameResults[i],
cover: coverUrl.url.replace("//", "https://"),
};
const newGames = gameResults.filter(
(game: Game) => game.id !== newGame.id
);
setGameResults([...newGames, newGame]);
})
.catch((error) => {
console.log("error", error);
});
await sleep(300);
}
console.log("finish");
};
useEffect(() => {
loadGamesImages();
}, [gameResults.length]);
Here is my problem : when React update the state, the old state is not there anymore. I explain : for the first cover, it's ok the new state has the first game covered. But when he make a new state for the second game, as you can see i get the gameResults state, but in this one the first game has no cover anymore.
Here is the result :
What have I done wrong ?
Each one of your looped asynchronous calls closes over the initial binding of the stateful gameResults - and gameResults starts out empty. For example, with the first Promise that resolves, these line:
const newGames = gameResults.filter(
(game: Game) => game.id !== newGame.id
);
setGameResults([...newGames, newGame]);
have the gameResults refer to the empty array, so setGameResults properly spreads the empty array plus the just-added newGame.
But then on further Promise resolutions, they also close over the initially-empty gameResults - all the async calls happened before the component re-rendered.
Use a callback instead, so that the async calls don't overwrite each other:
setGameResults((gameResults) => {
const newGames = gameResults.filter(
(game) => game.id !== newGame.id
);
return [...newGames, newGame];
});
(also note that there's no need to explicitly note the type of a parameter that TS can already infer automatically: (game: Game) can be just game)
Once this is working, I'd also suggest tweaking your code so that, when the effect hook runs again, only covers that have not been retrieved yet get requested again. This'll save you from unnecessarily making duplicate requests.

Resources