ReactJS Error when using map function, cannot read properties of undefined - reactjs

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

Related

How to get data when language changed in react V18.2?

I have problem with fetching data when language changed. I tried a lot of things that I found from Stack overflow, but unfortunately it just changing the direction and it didn't fetch the data based on language changed.
I fetching data with a custom hook and call it inside my functional component. let me share the code that I write.
Note: I'm using I18nextLng for translation.
App.js
import { RouterProvider } from "react-router-dom";
import Loading from './components/loading';
import routes from './routes/routes';
import { useEffect } from "react";
import i18n from "./utils/i18n";
function App() {
useEffect(() => {
let cleanup = true;
if (cleanup) {
i18n.on('languageChanged', (local) => {
let direction = i18n.dir(local);
document.body.dir = direction;
})
}
return () => {
cleanup = false;
};
}, []);
return (
<RouterProvider router={routes} fallbackElement={<Loading />} />
)
}
export default App;
LanguageSwitcher.js
import { useTranslation } from "react-i18next";
const LanguageSwitcher = () => {
const { i18n } = useTranslation();
return (
<select
className="form-select-sm rounded-pill text-center"
aria-label="Default select example"
value={i18n.language}
onChange={(e) =>
i18n.changeLanguage( e.target.value)
}
>
<option value="en">English</option>
<option value="fa">دری</option>
</select>
);
}
export default LanguageSwitcher;
Internships.js
import Image from "react-bootstrap/Image"
import { useFetchWebsiteData } from "../../hooks/website/useFetchWebsiteData";
import Loading from '../../components/loading'
import { useEffect, useState } from "react";
const Internships = () => {
let lang = localStorage.getItem("i18nextLng")
const { data, isLoading } = useFetchWebsiteData("getInternship", lang);
console.log("language changed", language);
return !isLoading ? (
<div className="container-fluid news-wrapper">
<div className="container">
<div className="row py-5">
<div className="col-md-12">
<div className="col-md-8">
<h4 className="title mb-4">{data?.title}</h4>
<p className="sub-title">{data?.content}</p>
</div>
<div className="col-md-2 text-center">
<Image
src={require("../../images/internships.png")}
fluid={true}
/>
</div>
</div>
</div>
</div>
</div>
) : (
<Loading />
);
}
export default Internships;
useFetchWebsiteData.js (Custom hook for fetching data)
import { useState, useEffect } from "react";
import { axiosPublic } from "../../utils/axios";
export const useFetchWebsiteData = (url,lang) => {
const [data, setData] = useState({});
const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState(false);
// const lang = localStorage.getItem("i18nextLng");
console.log('lang inside hook', lang)
useEffect(() => {
// const controller = new AbortController()
const fetchData = async () => {
setIsLoading(true);
await axiosPublic
.get(url, {
headers: { lang: lang === "fa" ? "dr" : "en" },
// signal: controller.signal,
})
.then((response) => {
if (response.status === 200) {
if (lang === "en") {
setIsLoading(false);
response.data.data.en.map((d) => {
let title = d.title;
let content = d.content;
return setData({ title: title, content: content });
});
}
if (lang === "fa") {
setIsLoading(false);
console.log("fa intern", response.data.data.dr)
response.data.data.dr.map((d) => {
let title = d.title;
let content = d.content;
return setData({ title: title, content: content });
});
setIsLoading(false);
}
} else {
setIsError(true);
}
})
.catch((error) => {
setIsLoading(false);
setIsError(true);
console.error(error.message);
});
};
fetchData();
// return () => {
// controller.abort()
// };
}, [url, lang]);
return { data, isLoading, isError };
};
I really appreciate for your helping.

ontrack is not firing in webrtc

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

TypeError: weatherData.map is not a function

I'm trying to map over data from API, but while writing the code to display the data I got this error: TypeError: weatherData.map is not a function
I tried removing useEffect from the code and tried to add curly brackets: const [weatherData, setWeatherData] = useState([{}])
Update: Line 14 log undefined : console.log(weatherData.response)
import axios from 'axios'
import { useEffect, useState } from 'react'
import './App.css'
function App() {
const [search, setSearch] = useState("london")
const [weatherData, setWeatherData] = useState([])
const getWeatherData = async () => {
try {
const weatherData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid={APIKEY}`);
console.log(weatherData.response);
if (weatherData) {
setWeatherData(weatherData);
}
} catch (err) {
console.error(err);
}
}
useEffect(() => {
getWeatherData()
}, [getWeatherData])
const handleChange = (e) => {
setSearch(e.target.value)
}
return (
<div className="App">
<div className='inputContainer'>
<input className='searchInput' type="text" onChange={handleChange} />
</div>
{weatherData.map((weather) => {
return (
<div>
<h1>{weather.name}, {weather.country}</h1>
</div>
)
})}
</div>
)
}
export default App
You're having errors in fetching the data as well as rendering it.
Just change the entire App component like this :
import { useEffect, useState } from "react";
import axios from "axios";
function App() {
const [search, setSearch] = useState("London");
const [weatherData, setWeatherData] = useState([]);
const APIKEY = "pass your api key here";
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid=${APIKEY}`
);
setWeatherData(result.data);
};
fetchData();
}, [search]);
const handleChange = (e) => {
setSearch(e.target.value);
};
return (
<div className="App">
<div className="inputContainer">
<input className="searchInput" type="text" onChange={handleChange} />
</div>
<h1>
{" "}
{weatherData.name} ,{" "}
{weatherData.sys ? <span>{weatherData.sys.country}</span> : ""}{" "}
</h1>
</div>
);
}
export default App;
this should be working fine just make sure to change : const APIKEY = "pass your api key "; to const APIKEY = "<your API key> ";
this is a demo in codesandbox
Create a promise function:
const getWeatherData = async () => {
try {
const weatherData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid={APIKEY}`);
console.log(weatherData.response);
if (weatherData.response.data) {
setWeatherData(weatherData.response.data);
}
} catch (err) {
console.error(err);
}
}
Then call it.

Uncaught (in promise) IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client_secret string

I'm working on a project where I am trying to integrate stripe. I'm trying to get payments to go through with one click of the placeOrderHandler button. Currently, when I click this button I get an error stating: Uncaught (in promise) IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client_secret string, and then if I click this button again it goes through and console.log(client_secret) provides the string associated with it. I'm unsure why this is happening, and I would really appreciate any help or advice on how to fix this. Thank you!
PlaceOrderScreen.js
import React, { useState, useEffect} from 'react';
import { useDispatch, useSelector, createSelector } from 'react-redux';
import {createOrder} from '../actions/orderActions';
import {listProducts} from '../actions/productActions';
import { ORDER_CREATE_RESET } from '../constants/orderConstants';
import { PAYMENT_SUCCESS } from '../constants/paymentConstants';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
import { loadStripe } from "#stripe/stripe-js";
import { Elements } from "#stripe/react-stripe-js";
import {CardElement, PaymentElement, CardNumberElement, CardExpiryElement, CardCvcElement, useStripe, useElements} from '#stripe/react-stripe-js';
import {payment, paymentInfo} from '../actions/paymentActions';
import LoadingSpinner from "../components/LoadingSpinner";
export default function PlaceOrderScreen(props) {
const cart = useSelector((state) => state.cart);
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
const paymentCreate = useSelector((state) => state.paymentCreate);
const { client_secret } = paymentCreate;
const paymentInformation = useSelector((state) => state.paymentInformation);
const {loadingPayment} = paymentInformation;
const userId = userInfo._id;
const orderCreate = useSelector((state) => state.orderCreate);
const { loading, success, error, order } = orderCreate;
const [loadedPay, setLoadedPay] = useState('');
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { products } = productList;
useEffect(() =>{
dispatch(listProducts({}));
}, [dispatch]);
const elements = useElements();
const stripe = useStripe();
const placeOrderHandler = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
console.log('Stripe.js has not yet loaded.')
return;
}
const paymentMethodType = 'card';
const currency = 'usd';
const {error: backendError} = dispatch(payment(paymentMethodType, currency, cart, userId, ));
if (backendError) {
//addMessage(backendError.message);
console.log(backendError)
return;
}
console.log('Client secret returned')
console.log(client_secret)
const {error: stripeError, paymentIntent} = await stripe.confirmCardPayment(client_secret,
{
payment_method: {
card: elements.getElement(CardNumberElement),
billing_details: {
name: cart.billingAddress.fullName,
},
},
},
)
if (stripeError) {
console.log('stripeError')
return;
}
cart.paymentId = paymentIntent.id
dispatch(createOrder({ ...cart, orderItems: cart.cartItems }))
const orderId = order._id;
setLoadedPay(false)
.then(dispatch(paymentInfo(orderId)))
setLoadedPay(true)
};
const [isLoading, setIsLoading] = useState(false);
var loaded = false;
useEffect(() => {
if (success ) {
props.history.push(`/order/${order._id}`)
dispatch({ type: ORDER_CREATE_RESET })
}
}, [dispatch, order, success]);
return (
<div>
{loadedPay === false ? (<LoadingBox></LoadingBox>) : (
<div>
{loadingPayment & loadingShipping ? (
<LoadingBox></LoadingBox>
) : (
<div>
{isLoading ? <LoadingSpinner /> :
<div>
<div className="row top">
<div className="col-2">
<ul>
<li>
<div className="card card-body">
<h2>Payment</h2>
<div>
<h1>Card</h1>
<form id="payment-form" >
<label htmlFor="card">Card</label>
{/*<CardElement id="card" />*/}
<CardNumberElement id="card"/>
<CardExpiryElement id="card"/>
<CardCvcElement id="card"/>
</form>
</li>
<li>
<button
type="button"
onClick={placeOrderHandler}
disabled={isLoading && cart.cartItems.length === 0}
className="primary block"
>
Place Order
</button>
</li>
{loading && <LoadingBox></LoadingBox>}
{error && <MessageBox variant="danger">{error}</MessageBox>}
</ul>
</div>
</div>
</div>
</div>
}
</div>
)}
</div>
)}
</div>
);
}
paymentReducer.js
export const paymentCreateReducer = (state = {client_secret:[]}, action) => {
switch (action.type) {
case PAYMENT_REQUEST:
return { ...state, loading: true };
case PAYMENT_SUCCESS:
return { ...state, loading: false, client_secret: action.payload};
case PAYMENT_FAIL:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
Backend
stripe.js
....
stripeRouter.get(
'/config',
expressAsyncHandler((req, res) => {
res.send({
publishableKey: '',
});
}));
stripeRouter.post(
'/pay',
expressAsyncHandler(async (req, res) => {
const userId = req.body.userId
const user = await User.findById(userId);
stripeClient.paymentIntents.create({
payment_method_types: [req.body.paymentMethodType],
amount: amount,
currency: req.body.currency,
})
.catch(function(err) {
console.log("There was an error"})
.then(async function(paymentIntents) {
const clientSecret = paymentIntents.client_secret
const client_secret = clientSecret.toString()
res.status(201).send(client_secret)
})
}));

Correct way to cleanup useEffect

I have useEffect callback which gives me an error:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
This is my code:
import React, {useEffect, useState} from 'react'
import { useTranslation } from 'react-i18next'
import firebase from 'firebase/app'
import '../firebase'
import Input from '../Components/Input'
import Button from '../Components/Button'
import { useHistory, useParams } from 'react-router-dom'
import { connect } from 'react-redux'
import { isAuth } from '../redux/actions/session/isAuth'
import Header from '../Modules/Header'
import Loader from '../Components/Loader'
import logo from '../media/logo/seanor_logo.svg'
let db = firebase.firestore()
const Login = ({setIsAuth, agencyData, userData, userUID, isAuth}) => {
const { t } = useTranslation()
let history = useHistory()
let { agency } = useParams()
// Change document title
document.title = `${t('login')}`
const [loading, setLoading] = useState(false)
// Input states
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState(false)
const [agencyErr, setAgencyErr] = useState(false)
useEffect( () => {
const checkUserType = () => {
// Check is user logged in and redirects to dashboard
if (userData !== null && isAuth) {
if (userData.type === 'employee') {
history.push(`/${agency}/dashboard/${userUID}`)
} else if (userData.type === 'crewagency') {
history.push(`/${agency}/crew-dashboard/`)
} else if ( userData.type === 'keyagency') {
history.push(`/${agency}/key-dashboard/`)
}
}
}
return () => checkUserType()
}, [agency, history, userData, userUID, isAuth])
const submit = () => {
setAgencyErr(false)
setLoading(true)
firebase.auth()
.signInWithEmailAndPassword(email, password)
.then(res => {
let resData = JSON.stringify(res.user)
resData = JSON.parse(resData)
let uid = resData.uid
// Check is usere belongs to agency
db.collection('users').doc(uid).get()
.then( res => {
let resData = JSON.stringify(res.data())
resData = JSON.parse(resData)
if (resData.data.agencyId === agency) {
// Check user type and redirect to dashboar by type
if (resData.data.type === 'employee') {
history.push(`/${agency}/dashboard/${uid}`)
} else if (resData.data.type === 'crewagency') {
history.push(`/${agency}/crew-dashboard`)
} else if ( resData.data.type === 'keyagency') {
history.push(`/${agency}/key-dashboard`)
}
} else {
firebase.auth().signOut()
setAgencyErr(true)
}
setLoading(false)
})
.catch(err => console.log('User info error', err))
setIsAuth(true)
})
.catch(err => {
console.log('Login error: ', err.message)
setError(true)
setLoading(false)
})
}
return (
<div>
{loading && <Loader />}
<Header />
<div className='login'>
<div className='login__box'>
<div className='login__logo'>
<img src={logo} alt='logo' />
</div>
<div className='login__box-title'>
<h2>{t('loginToCrewManager')}</h2>
</div>
<div className='login__input'>
<div className='login__input-label'>
{t('email')}
</div>
<Input
type='email'
handleInput={(value) => setEmail(value)}
/>
</div>
<div className='login__input'>
<div className='login__input-label'>
{t('password')}
</div>
<Input
type='password'
handleInput={(value) => setPassword(value)}
/>
</div>
{error &&
<div className='error'>
{t('loginError')}
</div>}
{agencyErr &&
<div className='error'>
{t('agencyErrorLogin')}
</div>}
<div className='login__submit'>
<Button
text='login'
handleClick={() => submit()}
/>
</div>
<div className='login__registration'>
<a href={`/${agency}/reset-password`}>{t('resetPasswordLogin')}</a>
</div>
<div className='login__registration'>
<a href={`/${agency}/registration`}>{t('newUserRegistration')}</a>
</div>
</div>
</div>
</div>
)
}
const mapStateToProps = state => {
return {
agencyData: state.agencyDataRed.obj,
isAuth: state.isAuthRed.bool
}
}
const mapDispatchToProps = dispatch => {
return {
setIsAuth: bool => dispatch(isAuth(bool))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
Maybe I'm not understand cleanup function? where is my mistake?
I think the problem is in your submit function and you're setting one the states after changing the url. I moved setLoading(false) a bit, try this:
const submit = () => {
setAgencyErr(false);
setLoading(true);
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((res) => {
let resData = JSON.stringify(res.user);
resData = JSON.parse(resData);
let uid = resData.uid;
// Check is usere belongs to agency
db.collection("users")
.doc(uid)
.get()
.then((res) => {
let resData = JSON.stringify(res.data());
resData = JSON.parse(resData);
if (resData.data.agencyId === agency) {
// Check user type and redirect to dashboar by type
if (resData.data.type === "employee") {
history.push(`/${agency}/dashboard/${uid}`);
} else if (resData.data.type === "crewagency") {
history.push(`/${agency}/crew-dashboard`);
} else if (resData.data.type === "keyagency") {
history.push(`/${agency}/key-dashboard`);
}
} else {
firebase.auth().signOut();
setAgencyErr(true);
setLoading(false); //<=== HERE
}
})
.catch((err) => console.log("User info error", err));
setIsAuth(true);
})
.catch((err) => {
console.log("Login error: ", err.message);
setError(true);
setLoading(false);
});
};
setIsAuth(true) is one the candidate that needs to be move to the right place

Resources