Heroku not running like it should after trying to post data i get a json object loading instead of a page - reactjs

I'm having problems with heroku. After i try to post data (post a listing), instead of being redirected to listings page where you would find a listing I just posted (that's how it works when i run it locally), the page displays a json object. And refresh doesn't work, i need to type the address again and then everything works normally, and the listing that i just posted is there as it should.
This is the front end
import { useState } from 'react'
import axios from 'axios'
import { useNavigate } from 'react-router-dom'
const PostListings = () => {
let navigate = useNavigate()
const [ newList, setNewListing ] = useState({
city: '',
neighborhood: '',
bedrooms: '',
price: '',
img: '',
reviews_id: []
})
const getNewListing = async () => {
console.log(newList)
await axios({
url: `${window.location.origin}/listings`,
method: 'post',
data: newList
})
}
const handleChange = (e) => {
setNewListing({...newList, [e.target.name]: e.target.value })
console.log(e.target.name)
console.log(e.target.value)
console.log(newList)
}
const handleSubmit= () => {
getNewListing()
navigate('/listings')
window.location.reload(false)
}
return (
<div>
<h2>Add A New Listing</h2>
<form className="submit-form" onSubmit={handleSubmit}>
<input type="text" value={newList.city} onChange={handleChange} name={'city'} placeholder={'city'} />
<input type="text" value={newList.neighborhood} onChange={handleChange} name={'neighborhood'} placeholder={'neighborhood'} />
<input type="text" value={newList.img} onChange={ handleChange} name={'img'} placeholder={'image'} />
<input type="text" value={newList.price} onChange={ handleChange} name={'price'} placeholder={'price'} />
<input type="text" value={newList.bedrooms} onChange={ handleChange} name={'bedrooms'} placeholder={'bedrooms'} />
<button>Submit</button>
</form>
</div>
)
}
export default PostListings
//this is in Controllers
const postListing = async (req, res) => {
try {
console.log('data:', req.body)
const listing = await new Listing(req.body)
console.log('new:', listing)
await listing.save()
return res.status(201).json({ listing })
} catch (error) {
return res.status(500).json({ error: error.message })
}
}
//and in index.js
app.post('/listings', listingsController.postListing)

Related

Param values are undefined during axios file upload along with text upload using FormData

I'm building a simple books management application. In a particular page, I need to upload a book's details along with a picture of the book.
I'm using formData and axios to do this. In the same request, sending the optional image as well as the text inputs.
But on reading the text fields from the body in the server side, all of them are undefined.
How can I resolve this issue ?
addBooksForm.js
import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import "./addbooksform.css";
import axios from "axios"
import { authContext } from "../../App";
const Addbooks = () => {
// eslint-disable-next-line
const [authDet, setAuthDet] = useContext(authContext);
const navigate = useNavigate()
const [values, setValues] = useState({
title: "",
author: "",
genreId: 1,
price: 0,
picture:null
});
const handleSubmit = async (e) => {
e.preventDefault();
let data = new FormData()
data.set("title", values.title)
data.set("author", values.author)
data.set("genreId", values.genreId)
data.set("price", values.price)
data.set("picture", values.picture)
console.log(values)
const response = await axios.post("http://localhost:5000/api/books/",data,
{
headers:{
Authorization:`Token ${authDet.accessToken}`
}
})
if (response.status === 200) {
navigate('/yourbooks');
} else {
console.log("Error occurred "+ response)
}
};
const onChange = (e) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
const onFileChange = (e) => {
setValues({...values, [e.target.name] : e.target.files[0] })
}
return (
<div className="addbooks">
<form onSubmit={handleSubmit}>
<h3>Title</h3>
<input type="text" name="title" required={true} onChange={onChange} value={values.title}/>
<h3>Author</h3>
<input type="text" name="author" required={true} onChange={onChange} value={values.author}/>
<h3>Genre</h3>
<input type="number" name="genreId" required={true} onChange={onChange} value={values.genreId}/>
<h3>Price</h3>
<input type="number" name="price" required={true} onChange={onChange} value={values.price}/>
<h3>Upload picture</h3>
<input type="file" name="picture" onChange={onFileChange}/>
<button>Add</button>
</form>
</div>
);
};
export default Addbooks;
I have also tried adding content-type:multipart/form-data in the config
Server side controller:
const addBooks = (e) => {
const { title, author, price, genreId } = req.body;
// further processing
}
here, all the fields are undefined
server.js:
app.use(express.urlencoded({extended:true}))
app.use(express.json())
app.use(cors())
Any help is appreciated. thanks in advance !!

How to pass data from parent to child (react Modal)?

I have a page users.jsx (parent) and a component DialogEditUser.jsx (child) and i would like to pass a specific data of a user that is located in parent to child by it's id (using find method)
This passed data should be loaded to its input in react modal as a value.
users.jsx Code:
import React, { useState, useEffect } from 'react'
import DialogAddUser from 'src/components/DialogAddUser'
import { getUsers} from 'src/Service/api'
const Typography = () => {
const [users, setUsers] = useState([])
useEffect(() => {
getAllUsers()
}, [])
const deleteUserData = async (id) => {
setConfirmDialog({
...setConfirmDialog,
isOpen: false,
})
await deleteUser(id)
getAllUsers()
setNotify({
isOpen: true,
message: 'Article Deleted Successfully.',
type: 'error',
})
}
const getAllUsers = async () => {
let response = await getUsers()
setUsers(response.data)
console.log(response.data)
}
return ( //... )
DialogEditUsers.jsx Code:
import { useEffect, useState } from 'react'
import { getUsers, editUser } from '../Service/api'
const initialValue = {
id: '',
code: '',
article: '',
price: '',
vat: '',
status: '',
company_id: '',
}
export default function DialogAddUser() {
const [user, setUser] = useState(initialValue)
const { code, article, price, vat, status, company_id } = user
const normalize = (v) => ({
code: v.code,
article: v.article,
price: Number(v.price),
vat: Number(v.vat),
status: Number(v.status),
company_id: Number(v.company_id),
})
useEffect(() => {
loadUserDetails()
}, [])
const loadUserDetails = async () => {
const response = await getUsers(id)
console.log('loading user details ', response)
setUser(response.data.find((x) => x.id == id))
}
const editUserDetails = async () => {
const response = await editUser(id, normalize(user))
console.log('Edit user details ', response)
}
const onValueChange = (e) => {
console.log(e.target.value)
setUser({ ...user, [e.target.name]: e.target.value })
}
return (
<>
<CModal
visible={visible}
onClose={() => setVisible(false)}
backdrop={'static'}
keyboard={false}
portal={false}
>
<CModalHeader>
<CModalTitle>Edit Article:</CModalTitle>
</CModalHeader>
<CModalBody>
<CForm>
<CFormInput
type="text"
id="exampleFormControlInput1"
label="Code :"
placeholder="Enter Code"
text=" "
aria-describedby="exampleFormControlInputHelpInline"
onChange={(e) => onValueChange(e)}
value={code}
name="code"
/>
<CFormInput
type="text"
id="exampleFormControlInput2"
label="Article :"
placeholder="Enter Article"
text=" "
aria-describedby="exampleFormControlInputHelpInline"
onChange={(e) => onValueChange(e)}
value={article}
name="article"
/>
//...the rest of inputs...
api.js Code:
import axios from 'axios'
const baseURL = 'https://api.factarni.tn/article'
const token =
'eyJhbGciOiJSUzI1NiIsImtpZCI6IjIxZTZjMGM2YjRlMzA5NTI0N2MwNjgwMDAwZTFiNDMxODIzODZkNTAiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiZmFraHJpIGtyYWllbSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BSXRidm1uMS12dWJJcHNxTURKMkNTcDhVcTlmU3I1LUI1T3Y3RHY2SFRNMT1zMTMzNyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9mYWN0YXJuaSIsImF1ZCI6ImZhY3Rhcm5pIiwiYXV0aF90aW1lIjoxNjYzNzY3ODk5LCJ1c2VyX2lkIjoiaWhqM0JWM0hIRFhpVnUwdmpzV3ZidjMyRDdMMiIsInN1YiI6ImloajNCVjNISERYaVZ1MHZqc1d2YnYzMkQ3TDIiLCJpYXQiOjE2NjM3Njc4OTksImV4cCI6MTY2Mzc3MTQ5OSwiZW1haWwiOiJmYWtocmlpLmtyYWllbUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJnb29nbGUuY29tIjpbIjEwODU1MTA3MjAwODIwNjMxMjI0NCJdLCJlbWFpbCI6WyJmYWtocmlpLmtyYWllbUBnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJnb29nbGUuY29tIn19.bvRTxHfPtJrQjF2BjXqhs7ji738kma55LMFVRb8jkeraWP-JRBi-LRPa0d7OR_-BPwCGuRBXIb6980_PP8wjhBeDdB5B77GujiGn3nUvpPOFeIaM0L7muw1NKo4YCtS3v6ifuywypTbL3_5x3SBFZEH-QV0sp5DAzaA-P3Fn8AwP66o3cUPHGengGpZNsfkJ0FYcqzH-xpyKVVWV'
//i dont mind sharing this token, it's for you to test this code if you need.
const config = { headers: { Authorization: `Bearer ${token}` } }
export const getUsers = async (id) => {
id = id || ''
try {
return await axios.get(`${baseURL}`, config)
} catch (error) {
console.log('Error while calling getArticles api ', error)
}
}
export const editUser = async (id, user) => {
return await axios.put(`${baseURL}/${id}`, user, config)
}
The only node error i'm getting in terminal using this code above (because i dont know how to pass the proper id of specified user) is:
src\components\DialogEditUser.jsx
Line 45:37: 'id' is not defined no-undef
Line 47:47: 'id' is not defined no-undef
Line 51:37: 'id' is not defined no-undef
For better explanation the problem (i dont know how to use online snippets sorry):
So what i'm expecting is: When i click on Edit button, i should get a modal with form that are filled with user data (code, article, price, vat, status and company_id) in each input of the form as value, just like this gif below:
Also, console.log(response.data) in users page shows this:
few days back i also faced the same issue. Solution for me is to create state in parent component and pass state to child. Example for it-
Parent Class
const parent= ()=>{
const [name, setName]= useState('')
const [password, setPassword]= useState('')
return(
<Child setName={setName} setPassword={setPassword} />
)
}
Child Class
const Child = ({setPassword,setName})=>{
return(
<div>
<input type="text" placeholder="Enter Name" onChange={(e)=>setPassword(e.target.value)} />
<input type="text" placeholder="Enter Name" onChange={(e)=>setPassword(e.target.value)} />
</div>
)
}
Hope my answer will help you to solve your problem, if you still facing issue, lemme know i will help you.
In users.jsx, pass props of (user.id):
<DialogEditArticle props={user.id} />
Then, in DialogEditArticle.jsx, create a new data and call in it props:
const DialogEditArticle = (data) => {
console.log(data.props)
Now console.dev, you will get all the ids of user in database (because button edit is inside map function).
Result:

React Hooks fetch post request memory leak

I'm trying to post a login form to my API after a validation callback (useForm) and set the response data in my authentication context (dispatch({ type: "SET_AUTH", payload: responseJson }). It works fine but I still get a memory leak warning. I've been working on this problem for a few days and i think i'm going crazy. I tried using ref and AbortController but can't fix this warning. Thanks for your help !
const Signin: React.FC = () => {
const { dispatch } = useAuthContext()
const isMountedRef = useRef<any>(null)
const defaultValue = {
email: '',
password: ''
}
const signinDefaultState = {
loading: false,
error: undefined,
data: undefined
}
type SigninState<T> = {
loading: boolean,
error?: string,
data?: T
}
const [signinState, signinSetState] = useState<SigninState<any>>(signinDefaultState)
const [validFormData, setValidFormData] = useState(defaultValue)
const validFormCallback = () => {
setValidFormData(values)
}
const { values, errors, handleChange, handleKeyup, handleSubmit } = useForm(
defaultValue,
validFormCallback,
validate,
)
useEffect(() => {
const abortController = new AbortController()
isMountedRef.current = true
if (validFormData.email !== "") {
const postSignin = async () => {
const options = {
...authJsonHeader,
method: "POST",
body: JSON.stringify(validFormData),
} as any
try {
signinSetState({ ...signinState, loading: true })
const response = await fetch(`${process.env.REACT_APP_API_HOST}/signin`, { ...options, signal: abortController.signal })
const responseJson = await response.json()
if (!response.ok) {
throw responseJson
}
if (isMountedRef.current) {
dispatch({ type: "SET_AUTH", payload: responseJson })
}
//signinSetState({ ...signinState, data: responseJson as string, loading: false })
} catch (err: any) {
console.log(err)
if (!abortController.signal.aborted) {
signinSetState({ ...signinState, error: err as string, loading: false })
}
}
}
postSignin()
}
return () => {
isMountedRef.current = false
abortController.abort()
}
}, [validFormData])
return (
<form>
<H3>Connecte-toi pour retrouver toutes tes popotes favorites et découvrir celles de tes proches</H3>
<div>
<InputField
id="email"
label="Email"
type="email"
name="email"
value={values.email}
onKeyUp={handleKeyup}
onChange={handleChange}
error={(errors as any).email}
/>
</div>
<div>
<InputField
id="password"
label="Password"
type="password"
name="password"
value={values.password}
onKeyUp={handleKeyup}
onChange={handleChange}
error={(errors as any).password}
/>
</div>
<div style={{ marginTop: "20px" }}>
<Button type="primary" onClick={handleSubmit}>Sign In</Button>
{signinState.error && <InfoBlockStyled>{signinState.error as any}</InfoBlockStyled>}
{signinState.loading && <LoadingInline />}
</div>
</form>
)
}
const InfoBlockStyled = styled(InfoBlock)(({ theme }) => ({
marginTop: theme.spacer.m,
}))
export default Signin

React "undefined" when posting with axios

Hello im trying to push some data to my API with axios and react but i keep getting undefined. i cant find my error what am i doing wrong would appreciate some help.
im using 2 components one to handle the inputs which seem to work i can see the fields filled with data
import { useState } from 'react'
export const useForm = (initialValues) => {
const [values, setValues] = useState(initialValues);
return [
values,
e => {
setValues({
...values,
[e.target.name]: e.target.values
});
}
]
}
and the component where do my API CALL
import "../Admin/admin.css";
import Axios from "axios";
import { useForm } from "./useForm";
// Displays booking with a person added.
const AddBookableTime = () => {
const [values, handleChange] = useForm({ startTime: '', endTime: '' })
const API_ENDPOINT = "https://localhost:44387/api/BookableHours";
const PostBookingTimes = async (e) => {
e.preventDefault()
let times = createBookingTimes(e);
try {
await Axios.post(`${API_ENDPOINT}`, times);
} catch (err) {
}
};
//Creating object to send to api
const createBookingTimes = (e) => {
let bookableHours = {
startTime: e.target.values.startTime,
endTime: e.target.values.endTime,
};
return bookableHours;
};
return (
<>
<form onSubmit={(e) => PostBookingTimes(e)}>
<input type="text" name="startTime" value={values.startTime} onChange={handleChange} ></input>
<input type="text" name="endTime" value={values.endTime} onChange={handleChange} ></input>
<button type="submit" value="Post" className="booking-button">
Lägg till ny bokningsbar tid
</button>
</form>
</>
);
}
export default AddBookableTime;

How to handle error and success response the cleanest way?

How would I show a server response error or success message the cleanest way ?
Right now, I'm using an async function to make an axios request, and on success/error im just updating a local state (with react-hook-form), but I feel like it's "ugly" and I want the pages to be as clean as possible and put the code to handle success and error messages in the service request, behind the scenes.
Example :
ForgotPassword.jsx
import React, { useState } from 'react';
import Layout from '../components/core/Layout';
import axios from 'axios';
import { useForm } from 'react-hook-form';
import { Button, Form, Alert } from 'react-bootstrap';
import { regex } from '../constants';
import { isAuth } from '../helpers';
import { forgotPassword } from '../services/User';
import { Redirect } from 'react-router-dom';
const Forgot = () => {
const {
handleSubmit,
register,
errors,
getValues,
setError,
setValue,
clearError
} = useForm({
mode: 'onBlur'
});
register({ name: 'responseError' });
register({ name: 'responseSuccess' });
const { responseSuccess } = getValues();
const onSubmit = async values => {
try {
const response = await forgotPassword(values);
setValue([{ responseSuccess: response.data.message }]);
// set response success msg to local state responseSuccess
} catch (error) {
setError('responseError', '', error);
// set response error msg to local state responseError
}
};
const forgotPasswordForm = () => (
<>
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Group>
<Form.Label>Email address</Form.Label>
<Form.Control
name='email'
ref={register({
required: true,
pattern: {
value: regex.email,
message: 'Invalid email address'
}
})}
type='email'
placeholder='Enter email'
isInvalid={errors.email}
/>
<Form.Control.Feedback type={errors.email ? 'invalid' : 'valid'}>
{errors.email && errors.email.message}
</Form.Control.Feedback>
</Form.Group>
<Button variant='primary' type='submit'>
Submit
</Button>
</Form>
<br />
{errors.responseError && (
<Alert
variant='danger'
dismissible
onClose={() => clearError('responseError')}>
{errors.responseError.message}
</Alert>
)}
</>
);
const forgotPasswordFormSuccess = () => (
<Alert
variant='success'
className='mt-5'
dismissible
onClose={() => setValue([{ responseSuccess: '' }])}>
{responseSuccess}
</Alert>
);
if (isAuth()) return <Redirect to='/' />;
return (
<Layout>
<div>
<h1>Forgot password</h1>
{responseSuccess ? forgotPasswordFormSuccess() : forgotPasswordForm()}
</div>
</Layout>
);
};
export default Forgot;
forgotPassword Function
export const forgotPassword = async ({ email }) => {
return new Promise(async (resolve, reject) => {
try {
const response = await Axios({
method: 'PUT',
url: `${process.env.REACT_APP_API}/forgot-password`,
data: { email }
});
resolve(response);
} catch (error) {
if (error.response) {
reject(error.response && error.response.data.error);
}
reject('Something went wrong. please try again later.');
}
});
};
Hope this is what you want
export const forgotPassword = ({ email }) => {
return new Promise((resolve, reject) => {
axios(`${process.env.REACT_APP_API}/forgot-password`, {
method: 'PUT',
data: { email }
})
.then(res => resolve(res.data))
.catch(err => reject(err))
});
};
const onSubmit = values => {
forgotPassword(values)
.then(res => setValue([{ responseSuccess: res.message }]))
.catch(err => setError('responseError', '', err));
};

Resources