I'm developing an ecommerce app with Firestore.
When a user deletes an item or adds an item - it's rendering properly.
But when I'm trying to empty the whole cart (delete doc), it's just not rendering without refresh.
Maybe it's about the deleted doc, so the the function cannot find the doc because there is no doc?
If so, what would be best practice solution here?
Here is the code:
import React, { useState, useEffect } from 'react'
import firebase from 'firebase';
import { useAuth, useStoreUpdate } from '../contexts/FirebaseContext';
import { Link, useHistory } from 'react-router-dom';
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';
export default function Cart() {
const [userMail, setUserMail] = useState(undefined)
const [userCart, setUserCart] = useState(undefined)
const [totalAmmout, setTotalAmmout] = useState(0)
const user = useAuth()
const userDoc = firebase.firestore().collection("cart").doc(userMail)
const updateStore = useStoreUpdate()
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
const history = useHistory()
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await console.log('ksaljdklasd');
await updateStore()
await console.log('dasdsad');
}
const updateCart = () => {
userDoc.get().then((doc) => {
if (doc.exists) {
let cart = doc.data()
setUserCart(cart)
}
})
}
const updateData = async () => {
if (user.currentUser) {
await updateCart()
if (userCart) {
let totalPrice = 0;
await userCart.item.forEach(item => {
totalPrice += item.price
})
await setTotalAmmout(totalPrice)
}
}
}
async function removeFromCart(itemId, name, url, price, category, type, description) {
const cartItem = { itemId, name, url, price, category, type, description }
await userDoc.update({
item: firebase.firestore.FieldValue.arrayRemove(cartItem)
})
await updateCart()
await updateStore()
}
useEffect(() => {
if (user.currentUser) {
setUserMail(user.currentUser.email);
updateStore();
}
}, []);
useEffect(() => {
updateData().then(
console.log(totalAmmout)
)
}, userCart);
if (!userCart) return <h1>hold</h1>
return (
<main className="main-cart">
<div className="container">
{userCart.item && userCart.item.length >= 1 && userCart.item.map((item) => {
return (
< div className="item-container" key={item.itemId} >
<h3>{item.name}</h3>
<p>${item.price}</p>
<img height="150px" width="150px" src={item.url} alt="" />
<button onClick={async () => {
await removeFromCart(item.itemId, item.name, item.url, item.price, item.category, item.type, item.description)
}}>X</button>
</div>
)
})}
</div>
<button className="fixed-bottom-link" onClick={onOpenModal}>finish</button>
<Modal showCloseIcon={true} open={open} onClose={onCloseModal} center>
<div className="modal-container">
<div>
{userCart &&
userCart.item.map(item => {
return (
<li>{item.name} <span className="strong">{'|$' + item.price}</span></li>
)
})
}
{totalAmmout &&
<h3>total price: ${totalAmmout}</h3>
}
</div>
<button onClick={emptyCart}>Click to Pay</button>
</div>
</Modal>
</main >
)
}
just had to reset the doc :
befor :
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await updateStore()
}
after :
const emptyCart = async () => {
const userDoc = await firebase.firestore().collection("cart").doc(userMail)
await userDoc.delete()
await userDoc.set({
item: firebase.firestore.FieldValue.arrayUnion()
})
await updateCart()
await updateStore()
}
Related
I am making a video calling application using react , webrtc and firebase. I am able to connect both local and remote connection but i am not receiving the remote mediastream. The ontrack function is not firing and i don't know why.
import logo from './logo.svg';
import { useEffect, useRef } from 'react';
import './App.css';
import { useState } from 'react';
import { initializeApp } from 'firebase/app'
import { addDoc, collection, doc, getDoc, getFirestore, onSnapshot, setDoc, updateDoc } from 'firebase/firestore'
function App() {
const myVideoRef = useRef(null)
const yourVideoRef = useRef(null)
const [cameras, setcameras] = useState()
const [myCallId, setmyCallId] = useState()
const [callId, setcallId] = useState()
const [roomId ,setroomId] = useState()
const servers = {
iceServers: [
{
urls: ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'],
},
],
iceCandidatePoolSize: 10,
}
const pc = new RTCPeerConnection(servers)
const firebaseConfig = {
// my config
}
const app = initializeApp(firebaseConfig)
const db = getFirestore(app)
async function getConnectedDevices(type){
const devices = await navigator.mediaDevices.enumerateDevices()
return devices.filter(device => device.kind === type)
}
async function openCamera(cameraId){
const constraints = {
'audio': {'echoCancellation': true},
'video': {
'deviceId': cameraId,
}
}
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
stream.getTracks().forEach((track) => {
pc.addTrack(track,stream)
})
myVideoRef.current.srcObject = stream
})
// this part is not firing.
let remoteStream = new MediaStream()
pc.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track)
})
}
yourVideoRef.current.srcObject = remoteStream
}
async function call(){
const callDoc = doc(collection(db,"calls"))
const offerCandidates = collection(callDoc,"offerCandidates")
const answerCandidates = collection(callDoc,"answerCandidates")
setmyCallId(callDoc.id)
pc.onicecandidate = (event) => {
console.log(event.candidate)
event.candidate && addDoc(offerCandidates,event.candidate.toJSON())
}
const offerDescription = await pc.createOffer()
await pc.setLocalDescription(offerDescription)
const offer = {
sdp: offerDescription.sdp,
type: offerDescription.type
}
await setDoc(callDoc, { offer } )
onSnapshot(callDoc, snapshot => {
const data = snapshot.data()
if(!pc.currentRemoteDescription && data?.answer){
const answerDescription = new RTCSessionDescription(data.answer)
pc.setRemoteDescription(answerDescription)
}
})
onSnapshot(answerCandidates, snapshot => {
snapshot.docChanges().forEach((change) => {
if(change.type === 'added'){
console.log(change.doc.data())
const candidate = new RTCIceCandidate(change.doc.data())
pc.addIceCandidate(candidate)
console.log(yourVideoRef.current.srcObject)
console.log(myVideoRef.current.srcObject)
}
})
})
}
async function answer(){
const callDoc = doc(collection(db,"calls"),callId)
const offerCandidates = collection(callDoc,"offerCandidates")
const answerCandidates = collection(callDoc,"answerCandidates")
pc.onicecandidate = (event) => {
event.candidate && addDoc(answerCandidates,event.candidate.toJSON())
}
const callData = (await getDoc(callDoc)).data()
console.log(callData)
const offerDescription = callData.offer
await pc.setRemoteDescription(new RTCSessionDescription(offerDescription))
const answerDescription = await pc.createAnswer()
await pc.setLocalDescription(answerDescription)
const answer = {
type: answerDescription.type,
sdp: answerDescription.sdp,
}
await updateDoc(callDoc, {answer})
onSnapshot(offerCandidates, snapshot => {
snapshot.docChanges().forEach((change) => {
console.log(change)
if(change.type === 'added'){
let data = change.doc.data()
pc.addIceCandidate(new RTCIceCandidate(data))
}
})
})
}
useEffect(() => {
async function fetch(){
const cameras = await getConnectedDevices('videoinput')
setcameras(cameras)
}
fetch()
},[])
return (
<div className="App">
<div className='flex flex-row'>
{cameras && cameras.map( camera => <h2 className='m-3' key={camera.deviceId} onClick={() => openCamera(camera.deviceId)} >{camera.label}</h2>)}
</div>
<div className='flex flex-row'>
<video className='w-1/2' ref={myVideoRef} autoPlay />
<video className='w-1/2' ref={yourVideoRef} autoPlay />
</div>
<button onClick={call} className='bg-gray-200'>Call</button>
<div className='flex flex-row'>
<input onChange={(e) => setcallId(e.target.value)} className='border-[4px] border-black' />
<button onClick={answer} className='bg-gray-200'>Answer</button>
</div>
<h2>{myCallId}</h2>
</div>
);
}
export default App;
The ontrack function is not firing. I have put the function in useEffect , on top outside all the functions, before setremotedescription but it is still not firing.
let remoteStream = new MediaStream()
pc.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track)
})
}
yourVideoRef.current.srcObject = remoteStream
I am trying to add a recipe to my favourites list but only if it's not in the list already.
I tried to fetch the favourites array and check for the same id, but it's not working. It doesn't take the array. When I console.log the array there is nothing. Please any help.
Here is the RecipeModel logic
import "./RecipeModel.css";
import { Link, NavLink, useNavigate, useParams } from 'react-router-dom';
import React, { useLayoutEffect, useState,useEffect, useContext } from 'react';
import * as userService from '../../../services/userService';
import { AuthContext } from "../../../contexts/AuthContext";
import * as likeService from '../../../services/likeService';
import useRecipeState from "../../EditRecipe/RecipeState";
const RecipeModel = ({recipe}) => {
const history = useNavigate();
const {user} = useContext(AuthContext);
const {recipeId} = useParams();
const [likes,setLikes] = useRecipeState(recipeId);
const [favourites,setFavourites] = useState([]);
useEffect(() => {
likeService.getLikes(recipe._id)
.then(likes => {
setLikes(state => ({...state, likes}))
})
}, []);
useEffect(() => {
userService.yourFavourites(user._id)
.then(result => {
setFavourites(result);
})
},[]);
const valid = !(favourites.some(i => i._id === recipe._id));
if(valid) {
const HandleFavourite = (e) => {
e.preventDefault();
console.log(`Recipe ${recipe._id}`);
const name = recipe.name;
const time = recipe.time;
const imageUrl = recipe.imageUrl;
const ingredients = recipe.ingredients;
const instructions = recipe.instructions;
userService.addFavourite({
name,
time,
imageUrl,
ingredients,
instructions
},user.accessToken)
.then(result => {
console.log(result);
console.log(index);
console.log(user._id);
history('/favourites');
})
}
}
const likeButtonClick = () => {
if (user._id === recipe._ownerId) {
return;
}
if (recipel.likes.includes(user._id)) {
return;
}
likeService.like(user._id, recipeId)
.then(() => {
setLikes(state => ({...state, likes: [...state.likes, user._id]}));
console.log('liked');
});
};
return (
<article className="articles">
<img className="img2" src={recipe.imageUrl}/>
<h1>{recipe.name}</h1>
<p className="cut-text">{recipe.instructions}</p>
<div className="btns1">
<Link smooth= "true" className="btnd" to={`/recipe-details/recipe-number:${recipe._id}`}>Details</Link>
<button className="like" onClick={likeButtonClick} > <i className="fas fa-solid fa-thumbs-up"></i> {likes.likes?.length || 0}</button>
<button className="favour" onClick={HandleFavourite} ><i className="fas fa-solid fa-heart-circle-plus"></i></button>
</div>
</article>
);
};
export default RecipeModel;
Thats the userService logic :
export const addFavourite = async (recipeData,token) => {
let response = await fetch(`${baseUrl}/favourites`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-Authorization': token,
},
body: JSON.stringify(recipeData)
});
let result = await response.json();
return result;
};
export const getAllFavourites = async () => {
let response = await fetch(`${baseUrl}/favourites`)
let recipes = await response.json();
let result = Object.values(recipes);
return result;
}
export const removeFavourite = (recipeId, token) => {
return fetch(`${baseUrl}/favourites/${recipeId}`, {
method: 'DELETE',
headers: {
'X-Authorization': token,
},
}).then(res => res.json());
};
export const getOneFav = (recipeId) => {
return fetch(`${baseUrl}/favourites/${recipeId}`)
.then(res => res.json())
};
export const yourFavourites = (ownerId) => {
let query = encodeURIComponent(`_ownerId="${ownerId}"`);
return request.get(`${baseUrl}/favourites?where=${query}`);
};
I'm trying to add a feature to add a picture to an album. They are connected through the album's id and picture's album_id. I can click on the album button and the picture will be added to that album but the page does not re-render. Also the handleAlbumID function runs before I even hit submit so I think that is where I am really confused...
Here is the PicturePage component:
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { getPictureThunk } from '../../store/picture';
import CommentsPage from '../comments/Comments.js';
import CreateComment from '../comments/PostComment';
import AddToAlbum from '../AddtoAlbum';
import { getAllAlbumsThunk } from '../../store/album';
import './pictures.css'
const PicturePage = () => {
const dispatch = useDispatch()
const { id } = useParams();
// const sessionUser = useSelector(state => state.session.user)
const pictureObj = useSelector(state => state.pictureReducer)
let picture = pictureObj.picture;
let wholeDate = pictureObj.picture?.created_at
let newDate = new Date(wholeDate).toUTCString();
let finalDate = newDate.split(' ').slice(0, 4).join(' ');
useEffect(() => {
dispatch(getPictureThunk(+id))
}, [dispatch])
const [users, setUsers] = useState([]);
useEffect(() => {
async function fetchData() {
const response = await fetch('/api/users/');
const responseData = await response.json();
setUsers(responseData.users);
}
fetchData();
}, []);
const picUser = users.find(user => user?.id === pictureObj.picture?.user_id )
useEffect(() => {
dispatch(getAllAlbumsThunk())
}, [dispatch])
return (
<>
<div>
<h1>{pictureObj.picture?.content}</h1>
<div className='pictureContainer'>
<div>
<div>Uploaded by {picUser?.username} on {finalDate}</div>
<br></br>
<img alt=''src={`${pictureObj.picture?.image}`}></img>
<CommentsPage/>
<CreateComment/>
</div>
<span>
<AddToAlbum picture={picture}/>
</span>
</div>
</div>
</>
)
}
export default PicturePage;
Here is the AddtoAlbum component I created:
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getAllAlbumsThunk } from '../store/album'
import { editPictureThunk } from '../store/picture';
const AddToAlbum = ({picture}) => {
const dispatch = useDispatch()
console.log('alPic', picture)
const sessionUser = useSelector(state => state.session.user)
const albumObj = useSelector(state => state.albumReducer)
const [albumID, setAlbumID] = useState(picture?.album_id)
let albums = Object.values(albumObj)
let usersAlbums = albums.filter(album => album?.user_id === sessionUser?.id)
// console.log("user", usersAlbums)
let specificAlbum = usersAlbums.find(album => album?.id === picture?.album_id)
let handleAlbumId = async (e) => {
e.preventDefault();
// console.log('e', e.target)
let updatedPicture;
console.log('alID', albumID)
updatedPicture = {
user_id: sessionUser?.id,
album_id: albumID,
content: picture?.content,
image: picture?.image
}
// }
console.log('pic', picture?.id)
return dispatch(editPictureThunk(+picture?.id, updatedPicture))
}
useEffect(() => {
dispatch(getAllAlbumsThunk())
}, [dispatch])
return (
<>
<h1>Album</h1>
<div className='albums-container'>
{picture?.album_id === null && (
<div>This picture currently doesn't belong to an album</div>
)}
{picture?.album_id && (
<div>In {specificAlbum?.title}</div>
)}
<div>
<form onSubmit={handleAlbumId}>
<ul>
{usersAlbums.map(({ id, title}) => (
<li className='album-container' key={id}>
<button
value={albumID}
onClick={() => setAlbumID(id)}
>{title}
</button>
</li>
))}
</ul>
<button type='submit'>Submit</button>
</form>
</div>
</div>
</>
)
}
export default AddToAlbum;
Here is my update route in Python:
#picture_routes.route('/<int:id>', methods=['PUT'])
def update(id):
foundPic = Picture.query.get(id)
user_id = request.json['user_id']
album_id = request.json['album_id']
content = request.json['content']
image = request.json['image']
if len(content) > 20:
return {'errors': "Title must be less than 20 characters"}
foundPic.user_id = user_id
foundPic.album_id = album_id
foundPic.content = content
foundPic.image = image
db.session.add(foundPic)
db.session.commit()
return foundPic.to_dict()
Here is my store:
export const editPicture = (id, updatedPic) => {
return {
type: EDIT_PICTURE,
id,
updatedPic
}
}
//Thunks
export const getAllPicturesThunk = () => async dispatch => {
const res = await fetch('/api/pictures')
if (res.ok) {
const pictures_obj = await res.json()
dispatch(getAllPictures(pictures_obj))
}
}
export const getPictureThunk = (id) => async dispatch => {
const res = await fetch(`/api/pictures/${id}`)
if (res.ok) {
const data = await res.json()
dispatch(getPicture(data))
}
}
export const postPictureThunk = (data) => async dispatch => {
const res = await fetch('/api/pictures/new', {
method: "POST",
body: data
})
if (res.ok) {
const newPic = await res.json()
if (newPic.errors) {
return newPic.errors
}
dispatch(postPicture(newPic))
// return newPic
}
// else {
// const error = await res.json()
// return error
// }
}
export const deletePictureThunk = (id) => async dispatch => {
const res = await fetch(`/api/pictures/${id}`,{
method: 'DELETE'
})
if (res.ok) {
const delObj = await res.json()
// console.log('deletedpic', delObj.id)
dispatch(deletePicture(delObj.id))
}
}
export const editPictureThunk = (id, data) => async dispatch => {
const res = await fetch(`/api/pictures/${id}`, {
method: 'PUT',
headers: {'Content-Type': "application/json"},
body: JSON.stringify(data)
})
if (res.ok) {
const updatedPic = await res.json()
// console.log('updatedPic', updatedPic.updated_pic)
if (updatedPic.errors) {
return updatedPic.errors
}
dispatch(editPicture(id, updatedPic))
return updatedPic
}
}
const initialState = {};
const pictureReducer = (state = initialState, action) => {
let newState;
switch(action.type) {
case GET_PICTURES:
newState = { ...state };
// action.payload.pictures?.forEach((picture) => newState[picture.id] = picture)
// return newState;
return action.payload
case SINGLE_PICTURE:
newState = {...state}
return action.payload
case POST_PICTURE:
newState = {...state}
newState[action.payload.id] = action.payload
// console.log('here', action.payload.picture)
return newState;
case DELETE_PICTURE:
newState = {...state}
delete newState[action.payload]
return newState
case EDIT_PICTURE:
newState = {...state}
newState[action.updatedPic.id] = action.updatedPic
return newState
default:
return state
}
}
I'm trying to make a sport/tinder like app for a school project from a friend of mine. It came together well on my localhost, but for him it was a requirement to host it online. Not really a professional in hosting, but I was a bit familiar with Heroku. I used a client and a server side for my application, so I build the client side and put it into the server side folder. This server side is hosted on the Heroku page. But whenever I try to login, it won't work and I get this error message in my console.
TypeError: Cannot read properties of undefined (reading 'map')
The error says it is caused by this line of code.
const matchedUserIds = matches.map(({user_id}) => user_id)
This is the whole MatchDisplay file that is used in my Dashboard. I'm using a MongoDB for the storage of my users.
import axios from "axios";
import { useEffect, useState } from "react";
import { useCookies } from "react-cookie";
const MatchesDisplay = ({ matches, setClickedUser }) => {
const [matchedProfiles, setMatchedProfiles] = useState(null);
const [cookies, setCookie, removeCookie] = useCookies(null);
const [matched, setMatched] = useState(null);
const matchedUserIds = matches.map(({ user_id }) => user_id);
const userId = cookies.UserId;
const getMatches = async () => {
try {
const response = await axios.get(
"https://[app].herokuapp.com/users",
{
params: { userIds: JSON.stringify(matched()) },
}
);
setMatchedProfiles(response.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getMatches();
}, [matches]);
const filteredMatchedProfiles = matchedProfiles?.filter(
(matchedProfile) =>
matchedProfile.matches.filter(
(profile) => profile.user_id === userId
).length > 0
);
return (
<div className="matches-display">
{filteredMatchedProfiles?.map((match) => (
<div
key={match.user_id}
className="match-card"
onClick={() => setClickedUser(match)}
>
<div className="img-container">
<img
src={match?.url}
alt={match?.first_name + "profile"}
/>
</div>
<h3>{match?.first_name}</h3>
</div>
))}
</div>
);
};
export default MatchesDisplay;
Any help is welcome. If you need more code examples, please reply ;)
EDIT
The ChatContainer that passes the user to the MatchesDisplay.
import ChatHeader from "./ChatHeader";
import MatchesDisplay from "./MatchesDisplay";
import ChatDisplay from "./ChatDisplay";
import { useState } from 'react';
const ChatContainer = ({user}) => {
const [ clickedUser, setClickedUser] = useState(null)
return (
<div className="chat-container">
<ChatHeader user={user}/>
<div>
<button className="option" onClick={() => setClickedUser(null)}>Matches</button>
<button className="option" disabled={!clickedUser}>Chat</button>
<button className="option" >Prices</button>
</div>
{!clickedUser && <MatchesDisplay matches={user.matches} setClickedUser={setClickedUser}/>}
{clickedUser && <ChatDisplay user={user} clickedUser={clickedUser}/>}
</div>
)
}
export default ChatContainer
The Dashboard that passes the user to the Chatcontainer.
import TinderCard from 'react-tinder-card';
import {useEffect, useState} from 'react';
import {useCookies} from 'react-cookie';
import ChatContainer from '../components/ChatContainer'
import axios from "axios";
const Dashboard = () => {
const [user, setUser] = useState(null)
const [genderedUsers, setGenderedUsers] = useState(null)
const [lastDirection, setLastDirection] = useState(null)
const [cookies, setCookie, removeCookie] = useCookies(['user'])
const [matchedUserIds, setMatchedUserIds] = useState(null)
const [filteredGenderedUsers, setFilteredGenderedUsers] = useState(null)
const userId = cookies.UserId
const getUser = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/user', {
params: {userId}
})
return setUser(response.data)
} catch (error) {
console.log(error)
}
}
const getGenderedUsers = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/gendered-users', {
params: {gender: user?.gender_interest}
})
return setGenderedUsers(response.data)
} catch (error) {
console.log(error)
}
}
useEffect(() => {
getUser()
}, [])
useEffect(() => {
setMatchedUserIds(user?.matches.map(({user_id}) => user_id).concat(userId))
if (user) return getGenderedUsers()
}, [user])
useEffect(() => {
if (genderedUsers) {
return setFilteredGenderedUsers(genderedUsers?.filter(
genderedUser => !matchedUserIds.includes(genderedUser.user_id)
))
}
}, [genderedUsers])
const updateMatches = async (matchedUserId) => {
try {
await axios.put('https://funfit-webpage.herokuapp.com/addmatch', {
userId,
matchedUserId
})
return getUser()
} catch (error) {
console.log(error)
}
}
const swiped = (direction, swipedUserId) => {
console.log(direction, swipedUserId)
if (direction === 'right') {
updateMatches(swipedUserId)
}
return setLastDirection(direction)
}
const outOfFrame = (name) => {
console.log(name + ' left the screen!')
}
return (<>
{user && <div className="dashboard">
<ChatContainer user={user}/>
<div className="swipe-container">
<div className="card-container">
{filteredGenderedUsers?.map((genderedUser) =>
<TinderCard
className='swipe'
key={genderedUser.user_id}
onSwipe={(dir) => swiped(dir, genderedUser.user_id)}
onCardLeftScreen={() => outOfFrame(genderedUser.first_name)}>
<div style={{backgroundImage: 'url(' + genderedUser.url + ')'}} className='card'>
<h3>{'Name: ' + genderedUser.first_name} <br/> {'Sport: ' + genderedUser.about}</h3>
</div>
</TinderCard>)}
<div className="swipe-info">
{lastDirection ? <p>You swiped {lastDirection}</p> : <p/>}
</div>
</div>
</div>
</div>}
</>)
}
export default Dashboard
I have 2 APIs, one call the products and the other one call the image of the products.
Products API: https://inventory.dearsystems.com/ExternalApi/v2/Product
The second API is required call the ID of the products
Image API: https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=
How can I call the second one to show the image.
Here is my code:
import axios from "axios";
import { useEffect, useState } from "react";
import { SingleContent } from "../../components/SingleContent/SingleContent";
export const All = () => {
const [content, setContent] = useState([]);
const fetchAllProducts = async () => {
const { data } = await axios.get('https://inventory.dearsystems.com/ExternalApi/v2/Product',{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
console.log(data.Products);
setContent(data.Products)
}
useEffect(() =>{
fetchAllProducts();
}, [])
return (
<div>
<h1 className="pageTitle">All Products</h1>
<div className="all">
{content && content.map((c) =>
<SingleContent
key={c.id}
id={c.ID}
name={c.Name}
sku={c.SKU}
category={c.Category}/> )}
</div>
</div>
)
}
Inside fetchAllProducts() you could map the data.Products array you get from the first request, call the second api for each item and add the product image to the item.
Then you can update the contents with the resulting array.
Edited: example code below.
const fetchAllProducts = async () => {
const { data } = await axios.get('https://inventory.dearsystems.com/ExternalApi/v2/Product',{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
const productsWithImage = data.Products
.map(async product => {
const imageUrl = await axios.get("https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=" + product.id)
return {...product, imageUrl }
})
setContent(productsWithImage)
}
// Then you can use product.imageUrl when you map your products
Use for instead of map because it was returning a Promise. The problem is that if setContent(result) is called outside of the for, it only returns on register.
See the code:
export const AllHandle = () => {
const [content, setContent] = useState([]);
const fetchAllProducts = async () => {
const { data } = await axios.get("https://inventory.dearsystems.com/ExternalApi/v2/Product?limit=10",{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
let result = [];
const totaProducts = await data.Products;
for (let product of totaProducts) {
const imageUrl = await axios.get(`https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=${product.ID}`, {
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
const imgUrl = imageUrl.data
result = [{ ...product, imgUrl}]
}
setContent(result)
}
useEffect(() =>{
fetchAllProducts();
}, [])
return (
<div>
<h1 className="pageTitle">All Products</h1>
<div className="all">
{content && content.map((c) =>
<SingleContent
key={c.ID}
id={c.ID}
name={c.Name}
sku={c.SKU}
category={c.Category}
attachment= { c.imgUrl[0].DownloadUrl}
/>
)}
</div>
</div>
)
}