Public API call working on Mozilla but not on Chrome (react-app) - reactjs

I recently tried to deploy my first react-app on to the web. The website is about looking up details for a certain pokemon and making your own card if you like.
I use Mozilla as my main browser and everything works pretty good. But when I ask for a pokemon request (GET) on chrome I don't get any results. If I have a look at the network console I get a 301 Error (from disk cache). What does this mean? You can look at my website at:
https://daan.boschmans.mtantwerp.eu/
I deployed my app using the npm run build command.
I added the .htaccess file in the public folder with the proper lines.
GET REQUEST:
export const getPokemonSprites = (name) => {
return fetch(`https://pokeapi.co/api/v2/pokemon-form/${name}`).then((response) => {
if(response.statusText === 'OK') {
return response.json();
}
throw new Error('Network response was not ok.');
})
}
export const getPokemonMoves = (name) => {
return fetch(`https://pokeapi.co/api/v2/pokemon/${name}`).then((response) => {
if(response.statusText === 'OK') {
return response.json();
}
throw new Error('Network response was not ok.');
})
}
This I how I handle the GET call:
getPokeData() {
if (this.state.searchValue && this.state.name !== this.state.searchValue) {
this.setState({ isLoading: true, hasError: false, name: "", sprites: [], moves: [], height: "", weight:"", specials: [], base_experience: "", type: [], stats:[], items: [], });
Promise.all([ getPokemonSprites(this.state.searchValue),getPokemonMoves(this.state.searchValue)])
.then( ([spriteList, pokeDetails]) => {
const sprites = Object.values(spriteList.sprites);
const moves = Object.entries(pokeDetails.moves);
const abilities = Object.entries(pokeDetails.abilities);
const types = Object.entries(pokeDetails.types);
const stats = Object.entries(pokeDetails.stats);
for (const [ , value] of Object.entries(moves)) {
this.state.moves.push(value[1].move.name);
}
for (const [, value] of Object.entries(types)) {
this.state.type.push(value[1].type.name);
}
for (const [, value] of Object.entries(abilities)) {
this.state.specials.push(value[1].ability.name);
}
for (const [, value] of Object.entries(stats)) {
let statsValue = `${value[1].stat.name}: ${value[1].base_stat}`;
this.state.stats.push(statsValue);
}
this.setState({sprites, name: spriteList.name, height: pokeDetails.height, weight: pokeDetails.weight, base_experience: pokeDetails.base_experience })
}).then(() => { this.setState({isLoading: false, searchValue: ""})})
.catch(() => { this.setState({isLoading: false, searchValue: "", hasError: true}) })
}
}
Any tips would be really appreciated
Thanks

Firstly, nice site. Looks like a fun little project.
I tried the website on Chrome and it works fine for me.
Looks as though you have a service worker that is caching content. If you used create-react-app, it comes with a service worker built it and looks as though it is caching the content of your API calls in your browser.
I suspect there is an issue with your Chrome's cache. You could try clearing the cache by following this suggestion here or alternatively it may be worth trying to reinstall chrome.

Related

How can i get the name of images and use the images

In product page, I want to get all images path that are in a specific folder and send those to client side, so I can use them in client side by passing the paths to Image component of next js. I tried this when I was developing my app via running npm run dev and it was successful. Then I pushed the changes to my GitHub repository and vercel built my app again. Now, when I go to the product page, I get an error from the server. I tried some ways to fix this problem, but I couldn't fix that. For example, I tried changing my entered path in readdir, but the problem didn't fix. Here are my codes:
const getPagePhotosAndReview = async (productName) => {
const root = process.cwd();
let notFound = false;
const allDatas = await fs
.readdir(root + `/public/about-${productName}`, { encoding: "utf8" })
.then((files) => {
const allDatas = { pageImages: [], review: null };
files.forEach((value) => {
const image = value.split(".")[0];
const imageInfos = {
src: `/about-${productName}/${value}`,
alt: productName,
};
if (Number(image)) {
allDatas.pageImages.push(imageInfos);
}
});
return allDatas;
})
.catch((reason) => (notFound = true));
if (notFound) return 404;
await fs
.readFile(root + `/public/about-${productName}/review.txt`, {
encoding: "utf-8",
})
.then((value) => {
allDatas.review = value;
})
.catch((reason) => {
allDatas.review = null;
});
return allDatas;
};
export async function getServerSideProps(context) {
if (context.params.product.length > 3) {
return { notFound: true };
}
if (context.params.product.length < 3) {
const filters = {
kinds: originKinds[context.params.product[0]] || " ",
};
if (context.params.product[1]) filters.brands = context.params.product[1];
const products = getFilteredProducts(filters, true);
if (products.datas.length === 0) {
return {
notFound: true,
};
}
return {
props: {
products: { ...products },
},
};
}
if (context.params.product.length === 3) {
const filters = {
path: context.resolvedUrl,
};
const product = getFilteredProducts(filters, false);
if (product.length === 0) {
return {
notFound: true,
};
}
const splitedPath = product[0].path.split("/");
const pagePhotosAndReview = await getPagePhotosAndReview(
splitedPath[splitedPath.length - 1]
);
if (pagePhotosAndReview === 404) return { notFound: true };
product[0] = {
...product[0],
...pagePhotosAndReview,
};
product[0].addressArray = [
textOfPaths[context.params.product[0]],
textOfPaths[context.params.product[1]],
];
return {
props: {
product: product[0],
},
};
}
}
This is the base code and I tried some ways but couldn't fix the problem. So to fix this problem, I want to ask: how can I get the name of all images in a specific directory and then use those images in client side? And errors that I get: if I go to a page directly and without going to the home of the website, I get internal server error with code of 500 and when I go to a page of my website, and then I go to my product page, I get
Application error: a client-side exception has occurred (see the browser console for more information).
And I should say that I know I should remove public from paths when I want to load an image from public folder. I did it but I still get error.

Apollo mutation that depends on a previous mutation in a for loop

I'm using react native and apollo client for an app that creates a chat given an array of selected users. My code looks like this:
const [addUser, {
data: userAdded, loading: addingUsers, error: errorAddingUsers,
}] = useMutation(ADDUSERTOCHAT)
const [makeChat, {
data: chat, loading: chatLoading, error: chatError,
}] = useMutation(NEWCHAT, {
variables: { ownerId: viewerId },
onCompleted: () => {
for (let i = 0; i < selectedFriends.length; i++) {
addUser({
variables: {
chatId: chat.newChat.id,
id: selectedFriends[i].id,
},
onCompleted: () => {
if (i === selectedFriends.length - 1) {
navigation.navigate('Chat', { chatId: chat.newChat.id })
}
},
})
}
},
})
Right now, this does not work. I am not sure how to run the addUser mutation only after the chat is created, and I'm also not sure if the for loop will work to run a mutation for every selected friend. I also need to navigate to the screen chat once everything in the process is done and I'm not sure if the condition I have will work for that. In sum, I'm a bit lost with how to sequence these mutations and can't get it to work. Any help is appreciated thanks!

React pass API data to chart

Background
I have an chart which displays static data just fine.
Using this template https://github.com/creativetimofficial/black-dashboard-react/blob/master/src/variables/charts.js
On my main page [dash.js] I have an API call, (which I tested presents the data I expect by using console.log().
I will be looking to have this data working dynamically so I have created it using useEffect and useState.
For reference;
const [chrtState, setChrtState] = useState({
loading: false,
chartos: null,
});
useEffect(() => {
setChrtState({loading: true});
const apiUrl = `http://example.com/api/request/`;
axios
.get(apiUrl, {
withCredentials: true,
})
.then(res => {
setChrtState({loading: false, repos: res.data.characters});
});
}, [setChrtState]);
const setCanvas = name => {
const apiUrl = `http://example.com/api/request/`;
axios
.get(apiUrl, {
withCredentials: true,
})
.then(res => {
setChrtState({loading: false, chartos: res.data.characters});
//console.log(res.data.characters);
});
};
return (
<Line
data={chartExample1[bigChartData + bigChartTime]}
options={chartExample1.options}
apiprops={chrtState.chartos}
/>
);
Note: the data parameter is used to select a specific chart-type (e.g. data1, data2, etc), this part works fine and isn't related to the APIdata as such.
My Problem
I am struggling to work out how to pass the API data to the chart.js
I tried using some other examples of how to pass props but it is proving very confusing for me given that it is already passing data1: (canvas) etc.
What I've tried
I tried to add an additional parameter before data1 (line 77) in charts.js, as follows;
apiprops: (props) => {
const {repos} = props;
console.log(repos);
},
but nothing was printed to the console for this.
I tried adding the data to canvas but this is already passing information used to render the height, width and style of the of the chart.
I have tried to add the API to the charts.js file, however when I add import axios from 'axios'; to the top of this page it throws out a syntax error. But I think it makes more sense to pull the API elsewhere and pass as a prop anyway. (please let me know if you disagree).
I am very much still building my knowledge of reactjs so thank you for any help and guidance on this!
End goal
For reference, my end goal will be to pass the API data to the chart and then process each dictionary into the labels and the datasets.data - the API passes in this order
{
"characters": [
{
"label": 123,
"data": 321
},
{
"label": 456,
"data": 654
}
]
}
I understood that you are trying to inject your API values into the existing functions in charts.js. First, you need to separate the API values into two arrays: labels and data. You can do that with reduce
const values = res.data.characters.reduce(
(acc, character) => ({
labels: [...acc.labels, character.label],
data: [...acc.data, character.data],
}),
{ labels: [], data: [] }
);
setChrtState({ loading: false, repos: values });
To inject them into the functions, you'll need to modify the functions a little using currying
data1: ({labels, data}) => (canvas) => {
...
return {
labels,
datasets: [
{
...
data,
},
],
};
},
and finally, call the function when passing the data prop to the Line component
<Line
data={chartExample1[bigChartData + bigChartTime](chrtState.repos)}
Although looking at those functions they seem to have the same code, is just the data is changing, you could use a single function.
UPDATE
this would be the complete version of the component
const [chrtState, setChrtState] = useState({
loading: true,
repos: null,
});
useEffect(() => {
setChrtState({ loading: true });
const apiUrl = `http://example.com/api/request/`;
axios
.get(apiUrl, {
withCredentials: true,
})
.then((res) => {
const values = res.data.characters.reduce(
(acc, character) => ({
labels: [...acc.labels, character.label],
data: [...acc.data, character.data],
}),
{ labels: [], data: [] }
);
setChrtState({ loading: false, repos: values });
});
}, [setChrtState]);
if (chrtState.loading) {
return <span>Loading</span>;
}
return (
<Line
data={chartExample1[bigChartData + bigChartTime](chrtState.repos)}
options={chartExample1.options}
/>
);

Storing images' URLs from firebase storage into firebase database - URLs are getting lost in cyberspace

It's a React app with Redux. A form collects a new recipe data from user. The data may include an array of file objects (images) selected by user for upload. I call it imagesToAdd. An action is called startAddRecipe. The following needs to happen:
Write new recipe to firebase database - this returns a ref.key needed for storing images in storage. - this works ok
If there are imagesToAdd a function uploadImages is called that uploads images to firebase storage and returns an array with uploaded images URLs. this works ok
Now the recipe created in (1.) above needs to be updated with the URLs obtained in (2.) - this does NOT work. console.logs are showing the URLs alright but they are not appearing in firebase database:
images
imageNames
0: "voteUpSmiley.png"
(no imageUrls)
...nor in the Redux store:
images: {
imageNames: [
'voteUpSmiley.png'
],
imageUrls: []
},
Oddly the redux-logger tool shows the data ok in console:
images:
imageNames: ["voteUpSmiley.png"]
imageUrls: ["https://firebasestorage.googleapis.com/v0/b/mniam-…=media&token=0e9b7991-0314-4f24-a94a-6b24f93baed7"]
The function uploadImages contains asynchronous tasks - firebase storage upload and a call for URLs so I await for the result and am getting correct one but it's not passed in time to subsequent statements because as said before the firebase database and the redux store are not getting the URLs. I've been looking at this for 2 days and seem to be going in circles.
I include the relevant code below for good people caring to have a look at it. Thank you.
export const startAddRecipe = (recipeData = {}) => {
return (dispatch, getState) => {
const {
authorEmail = '',
brief= '',
createdAt = 0,
ingredients = { general: [] },
keyWords = [],
preparation = { general: [] },
publishedAt = 0,
shared = false,
tips = '',
title = '',
votes = {
downs: [],
ups: [],
},
imagesToAdd = [],
} = recipeData
let imageNames = []
imagesToAdd.map(image => {
imageNames.push(image.name)
})
let recipe = {
authorEmail,
brief,
createdAt,
images: {
imageNames,
imageUrls: [],
},
ingredients,
keyWords,
preparation,
publishedAt,
shared,
tips,
title,
votes,
}
console.log('recipeB4', recipe); //this is showing URLs even before image upload???
database.ref(`recipes/`).push(recipe).then((ref) => {
console.log('ref.key:', ref.key);
if (imagesToAdd.length > 0) {
(async () => {
recipe.images.imageUrls = await uploadImages(ref.key, imagesToAdd)
console.log('recipeAfterImageUpload', recipe); // URLS are shown here but not reflected in the next line
database.ref(`recipes/${ref.key}`).update(recipe).then(() => {
console.log('RECIPE ADDED & UPDATED');
})
})()
}
dispatch(addRecipe({
id: ref.key,
...recipe,
}))
dispatch(startSetRecipeKeyWords())
})
}
}
const uploadImages = (id, imagesToAdd) => {
let imageUrls = []
imagesToAdd.map(image => {
const uploadTask = storage.ref(`/recipePics/${id}/${image.name}`).put(image)
uploadTask.on('state_changed',
(snapShot) => {
// console.log(snapShot)
},
(err) => {
// console.log(err)
},
() => {
storage.ref(`recipePics/${id}`).child(image.name).getDownloadURL()
.then(fireBaseUrl => {
console.log('fireBaseUrl', fireBaseUrl)
imageUrls.push(fireBaseUrl)
})
})
})
return imageUrls
}

How to reset recaptcha when using react-redux-firebase

I am working with React-Redux-Firebase. I implemented signing in with phone number. Now I am trying to implement error handling. When number is invalid I display window alert with error message. The only thing left to do is to reset recaptcha. Without it, I am getting error:
reCAPTCHA has already been rendered in this element
I was trying to do according to Firebase documentation
grecaptcha.reset(window.recaptchaWidgetId);
// Or, if you haven't stored the widget ID:
window.recaptchaVerifier.render().then(function(widgetId) {
grecaptcha.reset(widgetId);
}
but it does not work in my code. I dont have grecaptcha implemented. I tried to add it with react-grecaptcha, but it did not work.
Could someone give me a hint how to reset recaptcha after each error, please?
state = {
phone: "",
confirmationResult: {},
};
handleClick = () => {
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
}
);
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset(); // How can I do that?
});
};
I've been struggling with this problem for several days, maybe my answer will help someone.
export const requestRecaptchVerifier = () => {
window.recaptchaVerifier = new RecaptchaVerifier(
"recapcha-container",
{
size: "invisible",
},
auth
);
};
I then call signInWithPhone from another function and handle the error like this:
await signInWithPhone(formik.values.phone)
.then(() => {
// ... my code
})
.catch(() => {
window.recaptchaVerifier.recaptcha.reset();
window.recaptchaVerifier.clear();
});
All the difference in
window.recaptchaVerifier.recaptcha.reset()
And
window.recaptchaVerifier.clear()
I'm no expert but from the documentation and by talking with you in the comment section I think you need to pass a callback. Like this:
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
// reCAPTCHA solved, allow signInWithPhoneNumber.
firebase
.signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
.then((confirmationResult) => {
this.setState({ confirmationResult });
})
.catch((error) => {
// Error; SMS not sent
// Handle Errors Here
window.alert(`${error.code}, ${error.message}`);
recaptchaVerifier.reset();
});
}
});
Reference: https://firebase.google.com/docs/auth/web/phone-auth#use-invisible-recaptcha
Hope this helps!

Resources