Extracting images data from Promise (ReactJS and Axios) - reactjs

How do I get access to data stored as a Promise[] in ES6 array? I am loading an array from the backend and each object has a url for the image. So in order to render the image I have to async/await fetch the images for each object. Instead of returning a Base64 image, I get I promise with the image embeded deep in the promise. I need a way to read the image data. See image below for return object structure.
Please note that i use axios in the background and NOT the Fetch API
Below are the functions and service methods used to load the list and then the images in 2 steps.
1.1 Axios service method
listAllItems() {
return axios.get(API_URL + "docman/items/list/all");
}
1.2 ReactJS main function
async componentDidMount() {
try {
const items = await DocmanService.listAllItems();
const itemsData = items.data;
const data = await itemsData.map(item => {
const image = this.loadImage(item.image);
return { ...item, image: image }
})
this.setState({ items: data });
} catch (e) {
console.log(e);
}
}
2.1 Axios images service method
loadImage = (url) => {
return axios.get(API_URL + url, { responseType: 'arraybuffer' });
}
2.2 ReactJS image loader function
async loadImage(imageUrl) {
try {
return await ImageService.loadImage(imageUrl)
} catch (e) {
return '';
}
}
3.1 Json list fetched from backend
[
{
"id": "1",
"uuid": "1c0a33af-4e78-4823-b84e-f3b5464db2af",
"identifier": "EN ISO 8402",
"title": "EN ISO 8402 Quality Management - Vocabulary",
"folder": "e347fef9-0a76-4e62-b7f2-c78e9f88355b",
"media": "FILE",
"path": "document/id/105",
"image": "image/id/106",
"format": "PDF",
"authors": "",
"publishers": "",
"created": "2020-09-22T14:56:31.316+00:00",
"published": null,
"version": "1994",
"status": null
},
{
"id": "2",
"uuid": "16a0e658-b444-4b60-bf18-ba2786d5fb00",
"identifier": "ISO 14001",
"title": "ISO 14001 Environmenatl Management Systems - Requirements with Guidance for Use",
"folder": "e347fef9-0a76-4e62-b7f2-c78e9f88355b",
"media": "FILE",
"path": "document/id/107",
"image": "image/id/108",
"format": "PDF",
"authors": "",
"publishers": "",
"created": "2020-09-22T14:56:31.659+00:00",
"published": null,
"version": "2004",
"status": null
},
-
-
]

try doing image.then((data) => { // console.log(data) })

When you setState you are setting the new state with a list of objects with an image value that is a promise. Shouldn't you update the state only when at least one of the promise resolved to a real image?
Couldn't you do something like
this.loadImage(item.image).then((imageData=>setState(appropriate State)))?

Related

How to search for a specific data from a JSON file with array in Cypress?

I appreciate if someone help me in my question.
I need to validate a web page with 3 search fields. Also, I have a json file where I mocked it from the API.
So, I'm trying to type for a specific terminal and check if it works and it is not working. Instead of to show only the terminal number, the list is showing all the data.
I did the same validation with the API service and it worked as expected.
This is my code in Cypress
context('Search validation', () => {
beforeEach(() => {
cy.intercept(
'GET',
'**/mc-extratos/**',
{fixture: 'financeiro/carta-cancelamento'}
).as('verCartas')
cy.visit('/carta-de-cancelamento')
cy.get('[data-cy="consultarCartas"]')
.as('Buscar') // nome do botão
.click()
cy.wait('#verCartas')
})
it('Search by Terminal', () => {
cy.get('#nroTerminal')
.type('05009867')
cy.get('#Buscar').click()
cy.wait('#verCartas')
})
And this is the part of my JSON file.
{"status":
{
"value":"0",
"description":"Requisição efetuada com sucesso."
},
"data": [
{
"id": 0,
"ec": 11111111,
"ecComercio": 900212,
"ecName": "Estabelecimento 01",
"cardMask": "515590XXXXXX0001",
"nsu": "000150297",
"authorization": "011064",
"plan": "0212-parcelado lojista 12x",
"transactionDate": "2022-03-18T00:00:00Z",
"transactionValue": 212,
"cancelDate": "2022-03-28T16:20:23Z",
"cancelValue": 2,
"cancelCode": "00-Transac?o aceita",
"availableValue": 210,
"terminal": "05009867",
"product": "01-MASTERCARD",
"microFilm": null,
"channel": 990888,
"channelName": "Web Manual",
"user": "SISTEMA",
"currency": 986,
"currencyName": "Real",
"filter": null
},
{
"id": 264063,
"ec": 22222222,
"ecComercio": 831416,
"ecName": "Estabelecimento 02",
"cardMask": "515590XXXXXX0001",
"nsu": "852736414",
"authorization": "053768",
"plan": "0203-parcelado lojista 3x",
"transactionDate": "2022-03-03T00:00:00Z",
"transactionValue": 303,
"cancelDate": "2022-03-01T10:44:15Z",
"cancelValue": 303,
"cancelCode": "00-Transac?o aceita",
"availableValue": 0,
"terminal": "D5003826",
"product": "01-MASTERCARD",
"microFilm": "WS",
"channel": 990113,
"channelName": "WEB Service",
"user": "HOST",
"currency": 986,
"currencyName": "Real",
"filter": null
}
]
}
This is the web page where I have to write test in Cypress
You can use the yielded response body from the .wait() command.
cy.wait('#verCartas').then((res) => {
// parse response body and destructure the data array.
const { data } = JSON.parse(res.body)
// iterate through data array
data.forEach((element, index, array) => {
// Any validations you need to run using the data
// You'll probably want to identify the parent container element and select it using `.eq(index)`.
cy.get('.some-parent-container').eq(index).within(() => {
// code
});
});
});
It may be that reusing cy.get('[data-cy="consultarCartas"]') via the alias #Buscar is the problem.
Try using cy.get('[data-cy="consultarCartas"]') directly after setting the filter
it('Search by Terminal', () => {
cy.get('#nroTerminal')
.type('05009867')
cy.get('[data-cy="consultarCartas"]').click()
cy.wait('#verCartas')
cy.contains('tr', 'TERM')
.should('have.length', 1) // confirm filter worked
})

Change value from api response React

From a request call to the marvel API I receive the following
{
"id": 1011334,
"name": "3-D Man",
"description": "",
"modified": "2014-04-29T14:18:17-0400",
"thumbnail": {
"path": "http://i.annihil.us/u/prod/marvel/i/mg/c/e0/535fecbbb9784",
"extension": "jpg"
},
How can I change the thumbnail.path to be https instead of HTTP because when I deploy the app I get the warning of mixed content saying it will be change automatically
You can change the value of response after response received. for example:
axios.get('/post?ID=12345')
.then((response) => {
const modifiedResponse = response.data;
modifiedResponse.thumbnail.path =
modifiedResponse.thumbnail.path.replace("http", "https");
// I see you tagged react
this.setState({post: modifiedResponse});
})
Please share more code if it seems my answer is ambiguous.

Next-Auth | When user object have too many items then session request is without data

I will try to explain my problem as best as possible for me.
I'm using Strapi as a backend and Nextjs as a frontend.
For the authentication I using NextAuth.
[...nextauth].js:
const options = {
providers: [
Providers.Credentials({
name: 'Credentials',
credentials: {
username: { label: "Email", type: "email", placeholder: "jsmith" },
password: { label: "Password", type: "password" }
},
authorize: async (credentials) => {
try {
const user = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/auth/local`, {
identifier: credentials.username,
password: credentials.password,
});
if (user.data) {
return user.data
} else {
return null
}
} catch (error) {
const errorMessage = error.response.data.message[0].messages[0].message
throw new Error(errorMessage)
}
}
}),
],
database: process.env.NEXT_PUBLIC_DATABASE_URL,
session: {
jwt: true,
},
callbacks: {
jwt: async (token, user) => {
if (user) {
token.jwt = user.jwt;
token.user = user.user;
}
return Promise.resolve(token);
},
session: async (session, token) => {
session.jwt = token.jwt;
session.user = token.user;
return Promise.resolve(session);
},
},
pages: {
signIn: '/login',
error: '/login'
},
};
const Auth = (req, res) =>
NextAuth(req, res, options);
export default Auth;
When I send form with identifier and password I getting session response with user data and jwt.
Everything working well, but if user objects have few more objects assigned to him, then something goes wrong and the session is empty.
Example:
I creating in Strapi simple collection with just two fields - image field, and owner (relation to user). Every response with image contents few lines:
"photo": {
"_id": "60ca03fa20bd43033a53950e",
"name": "Zrzut ekranu 2021-06-16 o 14.59.48.png",
"alternativeText": "",
"caption": "",
"hash": "Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b",
"ext": ".png",
"mime": "image/png",
"size": 170.69,
"width": 668,
"height": 636,
"url": "/uploads/Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b.png",
"formats": {
"thumbnail": {
"name": "thumbnail_Zrzut ekranu 2021-06-16 o 14.59.48.png",
"hash": "thumbnail_Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b",
"ext": ".png",
"mime": "image/png",
"width": 164,
"height": 156,
"size": 14.92,
"path": null,
"url": "/uploads/thumbnail_Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b.png"
},
"small": {
"name": "small_Zrzut ekranu 2021-06-16 o 14.59.48.png",
"hash": "small_Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b",
"ext": ".png",
"mime": "image/png",
"width": 500,
"height": 476,
"size": 121.79,
"path": null,
"url": "/uploads/small_Zrzut_ekranu_2021_06_16_o_14_59_48_2bc223567b.png"
}
},
When I add 1 or 2 items with image and try to login to user who own that items then everything is fine, I can log in and receive full user object and jwt token.
But when I add 3 items there, session object is empty, and I can't log in. I do not receiving user object and jwt token.
With 3 items
With 2 items
When I using postman, even with 50 items response is good and include full user object and jwt token.
I think is because response is too large or something like that, but I have no clue how to deal with it.
I working on localhost (both - frontend and backend) on MacOS.
Is there anyone who can help me find a solution for that problem?
Kind Regards,
GP
The reason of above issue is that in api response is passed to many data, and next-auth store that all data in JWT, and JWT is stored in full in cookie, cookie is limited to 4096 bytes, and that simply brake that limit and response.
The simplest way to sort it out is to save only most important data in JWT.
You can do that in callback function.

Passing an Array of Objects to an Endpoint using Angular

I have a post request where the format of the data getting posted, is like this:
{
"gallery": [{
"id": 606,
"status": 1,
"name": "00000000606.png",
"title": "splash.png",
"location": "",
"caption": "",
"type": "image/png",
"charset": "binary",
"tags": "",
"width": 2732,
"height": 2732,
"size": 476358,
"embed_id": null,
"user": 1,
"date_uploaded": "2019-09-26T05:22:31-04:00",
"storage_adapter": "local",
"url": "/storage/uploads/00000000606.png",
"thumbnail_url": "/storage/uploads/thumbs/606.png",
"old_thumbnail_url": "/storage/uploads/thumbs/00000000606-png-160-160-true.jpg",
"html": null
}, {
"id": 610,
"status": 1,
"name": "00000000610.png",
"title": "icon.png",
"location": "",
"caption": "",
"type": "image/png",
"charset": "binary",
"tags": "",
"width": 1024,
"height": 1024,
"size": 274477,
"embed_id": null,
"user": 1,
"date_uploaded": "2019-09-26T06:43:44-04:00",
"storage_adapter": "local",
"url": "/storage/uploads/00000000610.png",
"thumbnail_url": "/storage/uploads/thumbs/610.png",
"old_thumbnail_url": "/storage/uploads/thumbs/00000000610-png-160-160-true.jpg",
"html": null
}]
}
This then creates a gallery slide show once the data is sent.
In order to compile this array, I have firstly uploaded the images using a drag and drop feature. This uploads to a files directory endpoint and when successfully returned in the response is pushed to an array in local storage. The above data is the local storage object array. So looks fine until I try to send it back up.
Once the rest of the form is filled in, I send the form values using a post method. The data all seems to be shaped correctly, but the server responds with a 500 error.
the error (which won't be familiar to some) as I am using Directus Headless CMS
this error arises when posting from Postman, as I don't get much back in terms of an error message.
{
"success": false,
"error": {
"message": "File not found at path: "
},
"code": 0,
"class": "League\\Flysystem\\FileNotFoundException",
"file": "/homepages/5/d755856449/htdocs/demo/vendor/league/flysystem/src/Filesystem.php",
"line": 386
}
.html
this is the culprit in the view:
<label tooltip="Add images of the product here" placement="right" show-delay="500">Product Gallery<span
class="question">?</span></label>
<ngx-file-drop dropZoneLabel="Drop files here" (onFileDrop)="galleryFilesDropped($event)"
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)">
<ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
Drag & Drop your Gallery Images onto Here.
<button class="update" type="button" (click)="openFileSelector()">Browse Files</button>
</ng-template>
</ngx-file-drop>
<label>Gallery Images</label>
<div class="gallery">
<ng-container *ngIf="!selectedGallery.length">
<div class="no_articles">
<img src="../../../assets/img/no_content-01.svg" alt="no-content icon">
<p>Currently, no gallery images exist, upload them above</p>
</div>
</ng-container>
<ng-container *ngFor="let image of selectedGallery">
<span>
<img class="placeholder" [src]="imageUrl + image.url" alt="selected image thumbnail">
<button class="delete" (click)="deleteImage()">Remove</button>
</span>
</ng-container>
</div>
and in the component.ts, this is the drop and post methods
image-drop method
public galleryFilesDropped(galleryImages: NgxFileDropEntry[], imageFile) {
this.galleryImages = galleryImages;
for (const droppedImage of galleryImages) {
if (droppedImage.fileEntry.isFile) {
const imageEntry = droppedImage.fileEntry as FileSystemFileEntry;
imageEntry.file((image: File) => {
let reader = new FileReader();
reader.readAsDataURL(image);
reader.onload = () => {
let data = reader.result;
let imageUpload = {
title: image.name,
name: image.name,
type: image.type,
size: image.size, data
}
this.configService.uploadImage(imageUpload)
.subscribe(
response => {
if (response) {
imageFile = response.data;
if (localStorage) {
var selectedImages;
if (!localStorage['selectedImages']) selectedImages = [];
else selectedImages = JSON.parse(localStorage['selectedImages']);
if (!(selectedImages instanceof Array)) selectedImages = [];
selectedImages.push(imageFile);
localStorage.setItem('selectedImages', JSON.stringify(selectedImages));
this.storageSubject.next(selectedImages);
}
}
}
)
}
});
} else {
const imageEntry = droppedImage.fileEntry as FileSystemDirectoryEntry;
console.log(droppedImage.relativePath, imageEntry)
}
}
}
the postProduct method
postProduct() {
let productCreate = {
product_category: this.selectedCategory, //posts fine
product_thumbnail: this.selectedImage,//posts fine
gallery: this.selectedGallery, <-- this doesn't send and breaks it
product_name: this.product_name,//posts fine
price: this.price,//posts fine
product_description: this.product_description,//posts fine
available_in_small: this.available_in_small,//posts fine
available_in_medium: this.available_in_medium,//posts fine
available_in_large: this.available_in_large,//posts fine
available_in_extra_large: this.available_in_extra_large,//posts fine
product_web_link: this.product_web_link,//posts fine
ad_click: this.ad_click//posts fine
}
this.storeService.createProduct(productCreate)
.subscribe(
response => {
if (response) {
this.product = response.data;
}
}
)
}
I have tried setting the gallery key value to:
gallery: {
data: JSON.parse(localStorage.getItem('selectedImages'))
},
and the same problem arises. The 500 error returns unknown, but from what I have learned from working this headless CMS, it will be due to the format of the data which is causing this.
I'm all out of ideas having tried a range of different ways to get this to work and I've now exhausted my subject knowledge and power of search to find a solution. Could some clever person possibly suggest what I'm doing wrong here?

Can't access the nested objects but can render the non-nested ones from API (using React hooks)

I'm a bit stumped on this problem I encountered trying to render the data from an API. Weird thing is I successfully fetched the data and I can render the values of properties in the array but the moment it becomes a nested property within an array it returns undefined. Do you by any chance know why?
location[0] + '&lon=' +
location[1] + '&APPID=8e6150cf719d58fc8062d507eaba92c0'
const [data, loading] = useFetch(url);
console.log(data.main.temp) // returns undefined
console.log(data.name) // logs name
The useFetch() is the following:
useEffect(() => {
async function fetchUrl() {
const response = await fetch(url);
const json = await response.json();
setData(json);
setLoading(false);
}
fetchUrl();
}, [url]);
return [data, loading];
}
export { useFetch };
The error message is:
TypeError: Cannot read property 'temp' of undefined
Data fetched looks like this:
{
"coord": {
"lon": 2.18,
"lat": 41.42
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}
],
"base": "stations",
"main": {
"temp": 293.81,
"pressure": 1013,
"humidity": 77,
"temp_min": 292.04,
"temp_max": 294.82
},
"visibility": 10000,
"wind": {
"speed": 2.6,
"deg": 120
},
"clouds": {
"all": 0
},
"dt": 1561061585,
"sys": {
"type": 1,
"id": 6414,
"message": 0.0074,
"country": "ES",
"sunrise": 1561004254,
"sunset": 1561058875
},
"timezone": 7200,
"id": 3124932,
"name": "el Clot",
"cod": 200
}

Resources