How to change value in input element? (reactjs) - reactjs

What I'm trying to do is that if user click on button 'Edit', modal is opened, and in value of input fields should be old, not updated value. But when I do that, I can't write anything else.
(eg. if user wants to update name, by opening modal EditUser, the old value of users name should be there, in input filed, and user needs to have opportunity to change that.)
<Input
type="text"
onChange={(e: any) => setFirstNameUpdated(e.target.value)}
value={props.userInfo.firstName}>
</Input>
i tried to use useRef:
const inputNameRef = useRef<HTMLInputElement | any>(null)
useEffect(() => {
console.log(inputNameRef.current) // this is null
console.log(props.userInfo.firstName) // this is OK
inputNameRef.current && (inputNameRef.current.value=props.userInfo.firstName)
}, [])
<Input
type="text"
onChange={(e: any) => setFirstNameUpdated(e.target.value)}
ref={inputNameRef}>
</Input>
EDIT:
SinglePost.tsx
import React, { useState, useRef, useEffect } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter, Button, FormGroup, Label, Input } from 'reactstrap'
import Axios from 'axios'
import '../user_profile/myprofile.css'
function UpdateProfile(props: any) {
const [firstNameUpdated, setFirstNameUpdated] = useState('')
const [lastNameUpdated, setLastNameUpdated] = useState('')
const [userBioUpdated, setUserBioUpdated] = useState('')
const inputNameRef = useRef<HTMLInputElement | any>(null)
useEffect(() => {
console.log(inputNameRef.current, props.userInfo.firstName)
inputNameRef.current && (inputNameRef.current.value = props.userInfo.firstName)
}, [])
// upload image
const [file, setFile] = useState('')
const [uploaded, setUploaded] = useState('')
const handleImageUpload = (e: any) => {
e.preventDefault();
setFile(e.target.files[0])
};
const onClickHandler = (e: any) => {
const formData = new FormData()
formData.append('fileImage', file)
Axios.post("/api/image", formData, {})
.then(res => {
//console.log(`UPLOADED: http://localhost:5000/${res.data.fileImage}`)
setUploaded(`http://localhost:5000/${res.data.fileImage}`)
})
.catch(err => console.log(err))
}
// update user
const updateUser = (e: any) => {
e.preventDefault()
props.setIsEditOpen(false)
const formData = new FormData()
formData.append('fileImage', file)
formData.append('first_name', firstNameUpdated)
formData.append('last_name', lastNameUpdated)
formData.append('user_bio', userBioUpdated)
const config: any = { header: { "Content-Type": "multipart/form-data" } }
Axios
.put(`/api/users/${props.userID}`, formData, config)
.then(res => {
const user = res.data
props.setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}
return (
<div>
{props.isEditOpen &&
<Modal isOpen={props.isEditOpen} toggle={() => props.setIsEditOpen(!props.isEditOpen)} backdrop="static">
<ModalHeader>Update your profile</ModalHeader>
<ModalBody>
<FormGroup>
<Label>Profile Image</Label>
<Input type="file" name="fileImage" onChange={handleImageUpload}></Input>
</FormGroup>
<Button onClick={onClickHandler} className="btn-upload-img">Upload file</Button>
<div className="inline">
{uploaded ? <img src={uploaded} style={{ width: "100px" }}></img> : <img src={props.userInfo.userPhoto} style={{ width: "100px" }}></img>}
</div>
<FormGroup>
<Label>First Name</Label>
<Input type="text" onChange={(e: any) => setFirstNameUpdated(e.target.value)} ref={inputNameRef} value={firstNameUpdated}></Input>
</FormGroup>
<FormGroup>
<Label>Last Name</Label>
<Input type="text" onChange={(e: any) => setLastNameUpdated(e.target.value)} defaultValue={props.userInfo.lastName}></Input>
</FormGroup>
<FormGroup>
<Label>About me</Label>
<Input type="text" onChange={(e: any) => setUserBioUpdated(e.target.value)} defaultValue={props.userInfo.userBio}></Input>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button color="success" onClick={updateUser} className="btn-update">Update</Button>
<Button color="danger" onClick={() => props.setIsEditOpen(false)}>Cancel</Button>
</ModalFooter>
</Modal>}
</div>
)
}
export default UpdateProfile
MyProfile.tsx
import React, { useState, useEffect, useContext } from 'react'
import './myprofile.css'
import Axios from 'axios'
import SinglePost from '../single_post/SinglePost'
import { AppContext } from '../context/AppContext'
import UpdateProfile from '../modals/UpdateProfile'
function MyProfile() {
const [userInfo, setUserInfo] = useState({
firstName: '',
lastName: '',
userBio: 'Write something about yourself.',
userPhoto: ''
})
const [isEditOpen, setIsEditOpen] = useState(false)
const { userID, setUserID } = useContext(AppContext)
// open modal on click 'edit'
const editUser = () => {
setIsEditOpen(true)
}
// get user data
const storedToken = localStorage.getItem('token')
useEffect(() => {
const config = {
headers: { "x-auth-token": `${storedToken}` }
}
Axios
.get('/api/auth/user', config)
.then(res => {
console.log('response', res)
const user = res.data.user
setUserID(user._id)
setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}, [])
return (
<div className="profile-container">
<button className="btn-edit" onClick={editUser}>
<i className="fa fa-edit"></i>
</button>
<div className="user-info">
<div className="img-circular">
<img className="user-profile-img2" src={userInfo.userPhoto}></img>
</div>
<p className="user-name">{userInfo.firstName} {userInfo.lastName}</p>
<p className="about-user">{userInfo.userBio}</p>
</div>
<div className="user-posts">
<p className="my-posts-title">My Posts</p>
</div>
{isEditOpen && <UpdateProfile
userID={userID}
setIsEditOpen={setIsEditOpen}
isEditOpen={isEditOpen}
setUserInfo={setUserInfo}
userInfo={userInfo}
/>}
{/* <SinglePost /> */}
</div>
)
}
export default MyProfile

Related

handleSubmit to call another function with event parameter

This is React JS.
I had a nice working sendData function that creates a new record on my json file.
It worked nice until I decided to add useForm to add some yup resolvers.
Now in the <form> tag here is onSubmit={}.
If I write here
<form onSubmit={handleSubmit(sendData(), onSubmit)}>, I get the error and nothing works as before.
enter image description here
I except to understand how handleSubmit works and how to resolve this problem.
Thanks in advance, guys!
my code:
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { Link, useNavigate } from 'react-router-dom';
import Confirmation from './Confirmation';
import * as yup from 'yup';
import { yupResolver } from '#hookform/resolvers/yup';
const schema = yup.object().shape({
name: yup.string().required(),
age: yup.number().positive().required(),
salary: yup.number().positive().required(),
email: yup.string().required(),
})
.required();
export default function LogIn() {
const { register, handleSubmit, formState: { errors }, } = useForm({
resolver: yupResolver(schema),
});
// for redirection
let navigate = useNavigate();
// modal for ghost mode
const [show, setShow] = useState(false);
const [details, setDetails] = useState({
name: '',
age: 0,
salary: 0,
email: ''
})
const sendData = async (event) => {
event.preventDefault()
const {name, age, salary, email} = details;
const res = await fetch("i hide the link :D",
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name, age, salary, email
})
})
navigate("/main");
}
const onSubmit = (data) => {
console.log(data)
}
return (
<div>
{show && <Confirmation show={show} setShow={setShow} />}
<div className="form-center">
<h1>Few Information</h1>
<form onSubmit={handleSubmit(sendData(), onSubmit)}>
<div className="form-controll">
<input type="text" {...register('name')} placeholder="Name"
onChange={(e) => setDetails({...details,name:e.target.value})}/>
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age')} placeholder="Age"
onChange={(e) => setDetails({...details,age:e.target.value})}/>
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="number" {...register('salary')} placeholder="Salary in $"
onChange={(e) => setDetails({...details,salary:e.target.value})}/>
{errors.salary?.message && <p>{errors.salary?.message}</p>}
<input type="email" {...register('email')} placeholder="Email"
onChange={(e) => setDetails({...details,email:e.target.value})}/>
{errors.email?.message && <p>{errors.email?.message}</p>}
</div>
<div className="forgot">
Don't want to share data?<br></br>
<button onClick={() => {setShow(true)}}>Ghost mode</button>
</div>
<div className="btn">
<input type='submit' value='Go' />
</div>
</form>
</div>
</div>
)
}
handleSubmit function is a wrapper for react-hook-form to manage your data inputs, validation, errors, etc.. before calling your own sendData function.
Consider doing:
export default function LogIn() {
const sendData = async (data) => {
const {name} = data;
// your post request
}
return (
<form onSubmit={handleSubmit(sendData}> // remove the useless onSubmit
<input
type="text"
{...register('name')}
placeholder="Name"
// remove the onChange prop
/>
</form>
)
}

Can't update the profile picture using cloudinary

I've tried to upload an image in Cloudinary and also want to save it into my database. Uploading an image in Cloudinary works fine but I can't save it into my database. Whenever I tried to do this it's only using the default image I've set in my model. Also likes setPic is working but for a moment and again it's changed to the default image. Please anybody help me figure out this problem.
Please comment if any other details if you need. Please help me.
Here is the Function
const postDetails = (pics) => {
setPicMessage(null);
if (pics?.type === 'image/jpeg' || pics?.type === 'image/png') {
const data = new FormData();
data.append('file', pics);
data.append('upload_preset', 'codeblogger_profile_image');
data.append('cloud_name', 'dhuej17x0');
fetch('https://api.cloudinary.com/v1_1/dhuej17x0/image/upload', {
method: 'post',
body: data,
})
.then((res) => res.json())
.then((data) => {
setPic(data.secure_url.toString());
console.log(pic);
})
.catch((err) => {
toast.error(err);
});
} else {
setPicMessage('Please Select an Image');
toast.error(picMessage);
}
};
And here is the full Profile.js File
import React, { useEffect, useState } from 'react';
import { Button, Col, Container, Form, InputGroup, Row } from 'react-bootstrap';
import { toast, ToastContainer } from 'react-toastify';
import { useDispatch, useSelector } from 'react-redux';
import { getUserDetails, updateUserProfile } from '../actions/userActions';
import { USER_UPDATE_PROFILE_RESET } from '../constant/userConstants';
const Profile = ({ history }) => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [pic, setPic] = useState();
const [password, setPassword] = useState('');
const [picMessage, setPicMessage] = useState();
const [confirmPassword, setConfirmPassword] = useState('');
const [passwordType, setPasswordType] = useState('password');
const [passwordType2, setPasswordType2] = useState('password');
const [showPass, setShowPass] = useState(false);
const [showPass2, setShowPass2] = useState(false);
const dispatch = useDispatch();
const userDetails = useSelector((state) => state.userDetails);
const { user } = userDetails;
// console.log(` this is from line 25 ${user}`);
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const userUpdateProfile = useSelector((state) => state.userUpdateProfile);
const { success } = userUpdateProfile;
useEffect(() => {
if (!userInfo) {
history.push('/login');
} else {
if (!user || !user.name || success) {
dispatch({ type: USER_UPDATE_PROFILE_RESET });
dispatch(getUserDetails('profile'));
} else {
setName(user.name);
setEmail(user.email);
setPic(user.pic);
}
}
if (success) {
toast.success('Profile Updated successfully');
}
showPass ? setPasswordType('text') : setPasswordType('password');
showPass2 ? setPasswordType2('text') : setPasswordType2('password');
}, [showPass, showPass2, dispatch, history, success, user, userInfo]);
const postDetails = (pics) => {
setPicMessage(null);
if (pics?.type === 'image/jpeg' || pics?.type === 'image/png') {
const data = new FormData();
data.append('file', pics);
data.append('upload_preset', 'codeblogger_profile_image');
data.append('cloud_name', 'dhuej17x0');
fetch('https://api.cloudinary.com/v1_1/dhuej17x0/image/upload', {
method: 'post',
body: data,
})
.then((res) => res.json())
.then((data) => {
setPic(data.secure_url.toString());
console.log(pic);
})
.catch((err) => {
toast.error(err);
});
} else {
setPicMessage('Please Select an Image');
toast.error(picMessage);
}
};
const submitHandler = (e) => {
e.preventDefault();
if (password !== confirmPassword) {
toast.error('Passwords do not match');
} else {
dispatch(updateUserProfile({ id: user._id, name, email, password }));
}
};
return (
<div className="profilePage mt-4 py-3">
<ToastContainer />
<Container>
<h2>PROFILE</h2>
<Row className="profileContainer">
<Col md={6}>
<Form onSubmit={submitHandler}>
<Form.Group controlId="name" className="mb-2">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
value={name}
placeholder="Name"
onChange={(e) => setName(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="email" className="mb-2">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="password" className="mb-2">
<Form.Label>New Password</Form.Label>
<InputGroup>
<Form.Control
type={passwordType}
placeholder="New Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<InputGroup.Text>
<i
onClick={() => setShowPass(!showPass)}
className={showPass ? 'fas fa-eye-slash' : 'fas fa-eye'}
style={{ cursor: 'pointer' }}></i>
</InputGroup.Text>
</InputGroup>
</Form.Group>
<Form.Group controlId="confirmPassword" className="mb-2">
<Form.Label>Confirm Password</Form.Label>
<InputGroup>
<Form.Control
type={passwordType2}
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<InputGroup.Text>
<i
onClick={() => setShowPass2(!showPass2)}
className={showPass2 ? 'fas fa-eye-slash' : 'fas fa-eye'}
style={{ cursor: 'pointer' }}></i>
</InputGroup.Text>
</InputGroup>
</Form.Group>
<Form.Group controlId="pic" className="mb-2">
<Form.Label>Change Profile Picture</Form.Label>
<Form.Control
onChange={(e) => postDetails(e.target.files[0])}
type="file"
accept=".jpeg,.png,.jpg"
custom="true"
/>
</Form.Group>
<Button
type="submit"
variant="success"
style={{ letterSpacing: '2px' }}>
UPDATE
</Button>
</Form>
</Col>
<Col
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<img src={pic} alt={user.name} className="profilePic" />
</Col>
</Row>
</Container>
</div>
);
};
export default Profile;
In submitHandler method, you are not passing pic variable in updateUserProfile.
use this
dispatch(updateUserProfile({ id: user._id, name, email, password, pic }));

Two times click is necessary to Login in ReactJS

I am trying to make a Login page and I am successful in some way. So here is my Login component:
import React, { useState, useEffect } from "react";
import Axios from "axios";
import useForm from "../components/LoginForm/useForm";
import validate from "components/LoginForm/validate";
import redtruck from "../assets/img/red-truck.png";
import auth from "../Authentication/auth";
import { withRouter } from "react-router";
const Login = ({ submitForm, history }) => {
const [isSubmitted, setIsSubmitted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [login, setLogin] = useState(false);
async function submitForm() {
setIsSubmitted(true);
try {
await fetchLogin(values.email, values.password);
if(login){
auth.login(() => {
history.push("/admin");
});
}
} catch (e) {
auth.login(() => {
history.push("/");
})
}
}
const { handleChange, values, handleSubmit, errors } = useForm(
submitForm,
validate
);
useEffect(() => {
if (localStorage.getItem("user-info")) {
submitForm();
}
}, []);
const fetchLogin = async (email, password) => {
try {
setLoading(true);
const res = await Axios({
method: "POST",
url: `url`,
headers: {
},
data: {
user_email: email,
user_password: password,
},
});
if (res.status === 200) {
setLogin(true);
localStorage.setItem("user-info", JSON.stringify(res.data));
}
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
return (
<>
<div>
<div className="form-container">
<div className="form-content-left">
<img className="form-img" src={redtruck} alt="spaceship" />
</div>
<div className="form-content-right">
<h1>SIGN IN</h1>
<form className="form" onSubmit={handleSubmit}>
<div className="form-inputs">
<label htmlFor="email" className="form-label">
Email address
</label>
<input
id="signin-email"
type="email"
name="email"
placeholder="Enter email"
className="form-input"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div className="form-inputs">
<label htmlFor="password" className="form-label">
Password
</label>
<input
id="signin-password"
type="password"
name="password"
placeholder="Password"
className="form-input"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p>{errors.password}</p>}
{login ? "" : <p>The password or the email is wrong</p>}
</div>
<button
variant="primary"
type="submit"
className="form-input-btn"
>
LOGIN
</button>
</form>
</div>
</div>
</div>
</>
);
};
export default withRouter(Login);
So the login state is set to true when email and password are right for the user. Later I want to use it when redirecting page to "/admin". But my problem is I have to click twice to login in the first place. Besides I am not sure, if the catch part is right:
catch (e) {
auth.login(() => {
history.push("/");
})
}
So I would be really glad, if you can give me some hint about it.
Thanks...
it is not that you have to press twice, you can check component state, sometimes React batches setState and then update value. You can look at this setState doesn't update the state immediately

React: Why sign up form is not creating new user in firebase users?

Here I'm trying to build a signup form using the react-hook form. I'm trying to build a restaurant website for my own purpose. But I have tried many times. But I'm getting many errors. First of all when I sign up a new user then firebase is not creating a new user. The form is not validating completely. But I can't find out the problem. Where is the problem? Can anyone help, please?
Here is my signUp.js file
import React, { useEffect, useState } from 'react';
import { useAuth } from './useAuth'
import { useForm } from 'react-hook-form';
import logo from '../../Images/logo2.png';
import './SignUp.css'
const SignUp = () => {
const [returningUser, setReturningUser] = useState(false);
const {register, handleSubmit, watch, errors} = useForm();
const auth = useAuth();
const onSubmit = data => {
if(returningUser){
if(data.email && data.password){
auth.signIn(data.email, data.password)
}
}
else{
if(data.name && data.email && data.password){
auth.signUp(data.email, data.password, data.name)
}
}
}
return (
<div className="sign-up">
<div className="container">
<div className="logo-container ">
<img src={logo} alt=""/>
</div>
{
returningUser ?
<form onSubmit={handleSubmit(onSubmit) } action="" className="py-5">
{
auth && auth.user != null && <p className="text-danger">{auth.user.error}</p>
}
<div className="form-group">
<input name="email" className="form-control" {...register('email', {requried: true})} placeholder="Email"/>
{errors && errors.email && <span className="error">Email is Required</span>}
</div>
<div className="form-group">
<input type="password" name="password" className="form-control" {...register('password', {requried: true})} placeholder="password"/>
{errors&& errors.password && <span className="error">Password is Required</span>}
</div>
<div className="form-group">
<button className="btn btn-danger">Sign In</button>
</div>
<div className="option text-center">
<label onClick={() => setReturningUser(false)}>Create a new Account</label>
</div>
</form>
:
<form action="" onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<input type="text" name="name" className="form-control"
{...register('name', {requried: true})} placeholder="Name"/>
{errors && errors.name && <span className="error">Name is Required</span>}
</div>
<div className="form-group">
<input type="email" name="email" className="form-control" {...register('email', {required: true})} placeholder="Email"/>
{errors && errors.email && <span className="error">Email is required</span>}
</div>
<div className="form-group">
<input type="password" name="password" className="form-control" {...register('password', {requried: true})} placeholder="Password"/>
{errors && errors.password && <span className="error">Password is Required</span>}
</div>
<div className="form-group">
<button className="btn btn-danger" type="submit">Sign Up</button>
</div>
<div className="option text-center">
<label onClick={() => setReturningUser(true)}>Already have an account!</label>
</div>
</form>
}
</div>
</div>
);
};
export default SignUp;
Here is my useAuth.js file
// import { faWindowRestore } from '#fortawesome/free-solid-svg-icons';
import firebase from "firebase/app";
import "firebase/auth";
import firebaseConfig from "../../firebase.config";
import { createContext, useContext, useEffect, useState } from "react";
import { Redirect, Route } from "react-router";
firebase.initializeApp(firebaseConfig);
const AuthContext = createContext();
export const AuthProvider = (props) => {
const auth = Auth();
return (
<AuthContext.Provider value={auth}>{props.children}</AuthContext.Provider>
);
};
export const useAuth = () => {
useContext(AuthContext);
};
export const PrivateRoute = ({ children, ...rest }) => {
let auth = useAuth();
return (
<Route
{...rest}
render={({ location }) =>
auth.user ? (
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location },
}}
/>
)
}
/>
);
};
const Auth = () => {
const [user, setUser] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const currentUser = user;
setUser(currentUser);
// ...
} else {
// User is signed out
// ...
}
});
}, []);
const signIn = (email, password) => {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((res) => {
// Signed in
setUser(res.user);
window.history.back();
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
});
};
const signUp = (email, password, name) => {
return firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((res) => {
// firebase
// .auth()
// .currentUser.updateProfile({
// displayName: name,
// })
// .then(() => {
setUser(res.user);
window.history.back();
})
// Signed in
// ...
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ..
});
};
const signOut = () => {
return firebase
.auth()
.signOut()
.then((res) => {
// Sign-out successful.
setUser(null);
})
.catch((error) => {
// An error happened.
});
};
return {
user,
signIn,
signUp,
signOut,
};
};
export default Auth;

React limits the number of renders to prevent an infinite loop

I am making an application and I have an error that I do not understand very well. Apparently, it is in the hook that I am using to make protected pages. I share the error and the code below.
Unhandled Runtime Error Error: Too many re-renders. React limits the
number of renders to prevent an infinite loop.
import firebase from "firebase";
const firebaseConfig = {
apiKey: "Key",
authDomain: "Domain",
databaseURL: "URL",
projectId: "Id",
storageBucket: "Bucket",
messagingSenderId: "SenderId",
appId: "appId",
measurementId: "measurementId",
};
// Initialize Firebase
!firebase.apps.length && firebase.initializeApp(firebaseConfig);
export const database = firebase.database().ref();
const mapUserFromFirebaseAuthToUser = (user) => {
const { displayName, email, uid } = user;
return {
userName: displayName,
email,
uid,
};
};
export const onAuthStateChanged = (onChange) => {
const emailProvider = new firebase.auth();
return emailProvider.onAuthStateChanged((user) => {
const normalizedUser = user ? mapUserFromFirebaseAuthToUser(user) : null;
onChange(normalizedUser);
});
};
export const loginUser = ({ email, password }) => {
const emailProvider = new firebase.auth();
return emailProvider.signInWithEmailAndPassword(email, password);
};
export const singUp = () => {
const emailProvider = new firebase.auth();
return emailProvider.signOut();
};
the page where the application breaks
import { useState, useEffect } from "react";
import styles from "styles/Countries.module.css";
import useUser, { USER_STATES } from "hooks/useUser";
import NavbarMenu from "components/navBar";
import Footer from "components/footer";
import { database } from "utils/firebase";
import {
Table,
Button,
Container,
Modal,
ModalBody,
ModalHeader,
ModalFooter,
FormGroup,
} from "reactstrap";
export default function Countries() {
const user = useUser();
const [timeLine, setTimeLine] = useState([]);
const [isOpenModalAdd, setIsOpenModalAdd] = useState(false);
const [isOpenModalEdit, setIsOpenModalEdit] = useState(false);
const [name, setName] = useState("");
const [currency, setCurrency] = useState("");
const [base, setBase] = useState("");
const [km, setKm] = useState("");
const [minute, setMinute] = useState("");
const [code, setCode] = useState("");
const [country, setCountry] = useState({
name: "",
currency_code: "",
base_fare: "",
per_km: "",
per_minute: "",
});
useEffect(() => {
database.child("Admin/Country").on("value", (snapshot) => {
setTimeLine(snapshot.val());
});
}, []);
const selectCountry = (data, id, status) => {
setCountry(data);
setCode(id);
status === "edit" && setIsOpenModalEdit(true);
};
const editCountry = () => {
database.child("Admin/Country/" + code).set(country);
resetModalAdd();
setIsOpenModalEdit(false);
};
const saveCountry = () => {
const MapCountry = {
name: name,
currency_code: currency,
base_fare: base,
per_km: km,
per_minute: minute,
};
database.child("Admin/Country/" + code).set(MapCountry);
resetModalAdd();
setIsOpenModalAdd(false);
};
const resetModalAdd = () => {
setName("");
setCurrency("");
setBase("");
setKm("");
setMinute("");
setCode("");
};
const openModalAdd = () => {
setIsOpenModalAdd(true);
};
const closeModalAdd = () => {
setIsOpenModalAdd(false);
};
const handleChangeName = (event) => {
const { value } = event.target;
setName(value);
let string = value;
let part = string.split("");
if (part.length === 2) {
let code = part[0].toUpperCase() + part[1].toUpperCase();
setCode(code);
}
};
const handleChangeData = (event) => {
const { value } = event.target;
setCountry(value);
};
const handleChangeCurrency = (event) => {
const { value } = event.target;
setCurrency(value);
};
const handleChangeBase = (event) => {
const { value } = event.target;
setBase(value);
};
const handleChangeKm = (event) => {
const { value } = event.target;
setKm(value);
};
const handleChangeMinute = (event) => {
const { value } = event.target;
setMinute(value);
};
return user ? (
<>
<div className={styles.container}>
<div className={styles.principalMenu}>
<NavbarMenu>
<div className={styles.titleHeader}>
<div className={styles.title}>Administration System</div>
<div className={styles.subtitle}>User: {user.userName}</div>
</div>
</NavbarMenu>
</div>
<div>
<h3>Country</h3>
</div>
<Container>
<Button color="primary" onClick={openModalAdd}>
New Country
</Button>
<Table>
<thead>
<tr>
<th>Name</th>
<th>Currency Code</th>
<th>Base Fare</th>
<th>Per Km</th>
<th>Per Minute</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{Object.keys(timeLine).map((i) => {
return (
<tr key={i}>
<td>{timeLine[i].name}</td>
<td>{timeLine[i].currency_code}</td>
<td>{timeLine[i].base_fare}</td>
<td>{timeLine[i].per_km}</td>
<td>{timeLine[i].per_minute}</td>
<td>
<Button
color="primary"
onClick={selectCountry(timeLine[i], i, "edit")}
>
Editar
</Button>
{" "}
<Button color="danger">Eliminar</Button>
</td>
</tr>
);
})}
</tbody>
</Table>
<Modal isOpen={isOpenModalAdd}>
<ModalHeader>Insertar Registro</ModalHeader>
<ModalBody>
<div className="form-group">
<label>Name: </label>
<br />
<input
type="text"
className="form-control"
value={name}
onChange={handleChangeName}
/>
<label>Currency Code: </label>
<br />
<input
type="text"
className="form-control"
value={currency}
onChange={handleChangeCurrency}
/>
<label>Base Fare: </label>
<br />
<input
type="text"
className="form-control"
value={base}
onChange={handleChangeBase}
/>
<label>Per Km: </label>
<br />
<input
type="text"
className="form-control"
value={km}
onChange={handleChangeKm}
/>
<label>Per Minute: </label>
<br />
<input
type="text"
className="form-control"
value={minute}
onChange={handleChangeMinute}
/>
</div>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={saveCountry}>
Guardar
</Button>
{" "}
<Button color="danger" onClick={closeModalAdd}>
Cancelar
</Button>
</ModalFooter>
</Modal>
<Modal isOpen={isOpenModalEdit}>
<ModalHeader>Editar Registro</ModalHeader>
<ModalBody>
<div className="form-group">
<label>Name: </label>
<br />
<input
type="text"
className="form-control"
name="name"
value={country.name}
onChange={handleChangeData}
/>
<label>Currency Code: </label>
<br />
<input
type="text"
className="form-control"
name="currency_code"
value={country.currency_code}
onChange={handleChangeData}
/>
<label>Base Fare: </label>
<br />
<input
type="text"
className="form-control"
name="base_fare"
value={country.base_fare}
onChange={handleChangeData}
/>
<label>Per Km: </label>
<br />
<input
type="text"
className="form-control"
name="per_km"
value={country.per_km}
onChange={handleChangeData}
/>
<label>Per Minute: </label>
<br />
<input
type="text"
className="form-control"
name="per_minute"
value={country.per_minute}
onChange={handleChangeData}
/>
</div>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={editCountry}>
Guardar
</Button>
{" "}
<Button color="danger" onClick={setIsOpenModalEdit(false)}>
Cancelar
</Button>
</ModalFooter>
</Modal>
</Container>
<Footer />
</div>
</>
) : user === USER_STATES.NOT_KNOWN ? (
<>
<div className={styles.container}>
<h1>Loading...</h1>
</div>
</>
) : (
<>
<div className={styles.container}>
<h1>Not authorized</h1>
</div>
</>
);
}
The hooks used for protected pages:
import { Router } from "next/router";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { onAuthStateChanged } from "utils/firebase";
export const USER_STATES = {
NOT_LOGGED: null,
NOT_KNOWN: undefined,
};
export default function useUser() {
const [user, setUser] = useState(USER_STATES.NOT_KNOWN);
const router = useRouter();
useEffect(() => {
onAuthStateChanged(setUser);
}, []);
useEffect(() => {
user === USER_STATES.NOT_LOGGED && router.push("/login");
}, [user]);
return user;
}
I hope this is enough to give me a hand. I have already tried to solve but the truth is I do not find the problem.
The logic in these lines is not correct:
useEffect(() => {
onAuthStateChanged(setUser);
}, []);
useEffect(() => {
user === USER_STATES.NOT_LOGGED && router.push("/login");
}, [user]);
I understand the first useEffect is used to update the state,
but the second useEffect watches this state and returning boolean?
Instead of user === USER_STATES.NOT_LOGGED && router.push("/login");, it should be:
if (USER_STATES.NOT_LOGGED) { router.push("/login"); }

Resources