axios post method just not responding with anything - reactjs

i have this axios post method in my Action creator in my reactJS app but for some reason, I don't understand why, the post method is frozen and doesn't do anything. I have a similar implementation in my one of the other project that's working fine but this isn't. The console.log() shows nothing, no error no response. Please help, thanks in advance.
export const addNewPost = (data) =>(dispatch) => {
dispatch(newPostLoading);
console.log("addNewPost triggered");
return (dispatch) => {
axios
.post("/posts.json", data)
.then((response) => {
console.log(response.data);
dispatch(newPostSuc());
})
.catch((err) => {
console.log(err);
dispatch(newPostFailed(err));
});
};
};
This is what my caller component looks like :
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { Button, Row, Col, Label } from 'reactstrap';
import { Control, LocalForm } from 'react-redux-form';
import { addNewPost } from '../redux/ActionCreators';
import {Loading} from './LoadingComponent';
class NewPost extends Component {
addPostHandler = (event) => {
const data ={
title: event.title,
author: event.author,
content: event.content,
image:''
}
this.props.addNewPost(data);
};
render() {
if(this.props.newPost.isLoading)
{
return (<Loading/>);
}
let redirectElement = null;
if (this.props.newPost.redirect) {
redirectElement = <Redirect to="/" />;
}
return (
<>
{redirectElement}
<div className="container">
<LocalForm onSubmit={(values) => this.addPostHandler(values) }>
<Row className="form-group">
<Label htmlFor="title" md={2}><strong>Post Title</strong></Label>
<Col md={10}>
<Control.text model=".title" id="title" name="title"
placeholder="Catchy title here bitch"
className="form-control"
/>
</Col>
</Row>
<Row className="form-group">
<Label htmlFor="author" md={2}><strong>Author</strong></Label>
<Col md={10}>
<Control.text model=".author" id="author" name="author"
placeholder="Author"
className="form-control"
/>
</Col>
</Row>
<Row className="form-group">
<Label htmlFor="content" md={2}><strong>Post Description</strong></Label>
<Col md={10}>
<Control.textarea model=".content" id="content" name="content"
rows="12" placeholder="You saw shit? Time to step on it"
className="form-control" />
</Col>
</Row>
<Row className="form-group">
<Col md={{size:10, offset: 2}}>
<Button type="submit" color="primary">
Send Post
</Button>
</Col>
</Row>
</LocalForm>
</div>
</>
);
}
}
const mapStateToProps = (state) => {
return {
newPost: state.newPost
};
};
const mapDispatchToProps = (dispatch) => {
return {
addNewPost: (data) => {dispatch(addNewPost(data))}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(NewPost);

Related

Why do i get error 400 on my graphQL mutation create user

I'm working with Reactjs and GraphQL integration. i got a problem when i'm doing mutation for new user.
Scenario :
Creating user using Modals bootstrap. when successful create new user, it shows alert or information success.
Code :
Here's my ModalCreate component code.
import React, { useState, useEffect } from 'react';
import { Button, Modal, Form } from "react-bootstrap";
const ModalCreate = (props) => {
// state for check input component
const [value, setValue] = useState({
username: props.username || '',
email: props.email || '',
fullname: props.full_name || '',
password: props.password || '',
phone: props.phone || '',
address: props.address || '',
groupid: props.group_id,
});
const onChange = event => {
setValue({
...value,
[event.target.name]: event.target.value
})
}
useEffect(() => {
if (props.show) {
document.body.classList.add("modal-open");
}
return () => {
if (document.body.classList.contains("modal-open")) {
document.body.classList.remove("modal-open");
}
};
}, [props.show]);
return (
<Modal show={props.show}>
<Modal.Header>
<Modal.Title> <span>FORMULIR AKUN PENGGUNA</span> </Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={e => {
e.preventDefault();
props.action({
variables: {
...value
}
})
}}>
<Form.Group className="mb-3">
<Form.Label>Role Akun</Form.Label>
<Form.Select aria-label="pilih user role" value={value.groupid} onChange={onChange}>
<option value="superadmin">Super Admin</option>
<option value="admin">Admin</option>
<option value="admin_rj ">Admin RJ</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Username</Form.Label>
<Form.Control name="username" value={value.username} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Nama Lengkap</Form.Label>
<Form.Control name="fullname" value={value.fullname} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Email</Form.Label>
<Form.Control type="email" name="email" value={value.email} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Password</Form.Label>
<Form.Control type="password" name="password" value={value.password} onChange={onChange}/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Phone</Form.Label>
<Form.Control type="text" name="phone" value={value.phone} onChange={onChange}/>
</Form.Group>
<Button variant="secondary" type='submit'>
Simpan
</Button>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={props.onClose}>
Keluar
</Button>
</Modal.Footer>
</Modal>
);
};
export default ModalCreate;
and action/performing mutation in page call index.js :
import React, { useState } from 'react';
import { useQuery, useMutation } from '#apollo/client';
import { Container, Card, Button, InputGroup, FormControl, Form, Spinner } from 'react-bootstrap';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faSearch } from '#fortawesome/fontawesome-free-solid';
import CardInfo from '../../../component/PengaturanPengguna/CardInfo';
import TableUserInfo from '../../../component/PengaturanPengguna/Table';
import { Loading } from '../../../component/Common';
import ModalCreate from '../../../component/PengaturanPengguna/Modals/ModalCreate';
import { GET_ALL_USERS, GET_USER_BY_ID } from '../../../gql/query';
import { REGISTER_USER } from '../../../gql/mutation';
const SearchInput = () => {
return (
<InputGroup className="mb-3">
<InputGroup.Text>
<FontAwesomeIcon icon={faSearch} />
</InputGroup.Text>
<FormControl
type="text"
placeholder="Search..."
/>
</InputGroup>
)
}
const PengaturanPengguna = (props) => {
// refetch and query data
const { data: usersdata, loading: usersloading, error: userserror } = useQuery(GET_ALL_USERS);
const { refetch, loading } = useQuery(GET_ALL_USERS);
// show modals
const [showModal, setShowModal] = useState(false);
// mutation new register user
const [registerUser, { loading: registerloading, error: registererror }] = useMutation(REGISTER_USER, {
refetchQueries: [{ query: GET_USER_BY_ID }, { query: GET_ALL_USERS }],
onCompleted: data => {
console.log(data)
},
onError: err => {
console.error(err);
}
}) ;
const handleRefreshClick = () => {
refetch();
}
const handleShowModal = () => setShowModal(true);
const handleCloseModal = () => setShowModal(false);
if (usersloading || registerloading) return <Loading/>
if (userserror || registererror) return <p>Error!</p>
return (
<Container>
<CardInfo/>
<Card>
<Card.Title>
<span className='base-md text-regular mt-2 std-txt-primary-200'>Data Pengguna Dashboard</span>
</Card.Title>
<Card.Body>
<div className='d-flex justify-content-between'>
<Form inline>
<SearchInput/>
<Button variant='secondary' onClick={handleRefreshClick} disabled={loading}>{loading ? ( <Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"/> ) : 'Muat Ulang'}</Button>
</Form>
<div>
<Button variant='success' onClick={() => { setShowModal(true) }}>Daftar Akun</Button>
</div>
</div>
<TableUserInfo users={usersdata}/>
</Card.Body>
</Card>
{
showModal ? <ModalCreate show={handleShowModal} onClose={handleCloseModal} action={registerUser} /> : null
}
</Container>
)
}
export default PengaturanPengguna;
and here's my mutation :
const REGISTER_USER = gql`
mutation($input: RegisterInput!) {
register(input: $input) {
username
email
full_name
phone
address
group_id
}
}
`;
Error :
I got this error
Also, Network Status Tabs :
I've been try any solution but it still not working, any help will be appreciated, thank you
If you are getting validation error from apollo for required fields then check the form fields may be name attribute is missing and value is not storing inside your state.

Redux form, loses focus after keypress?

Im experiencing a bit of a weird problem.
I have a form where I have an input field, but after i trigger an onChange event with a keypress it loses focus from the input field...
{editPhoneEnabled && <Field
name="phoneNumber"
component={phoneFieldRenderer}
validate={[Validator.required, Validator.phone]}
/>}
const phoneFieldRenderer = ({ input }) => {
return (
<ReactTelInput {...input} />
)
}
I've seen this example setup where the problem occurs (https://codepen.io/invisiblecomma/pen/wqLaZQ), but i've done the similar as you can see, but it still doesnt work?
Any ideas out there to help me understand what is going on?
The whole component:
import React, { useState, useEffect } from 'react';
import { Field, reduxForm, getFormValues } from 'redux-form';
import { Col, FormGroup } from 'reactstrap';
import { t } from 'Utilities/i18n';
import Validator from 'Utilities/validation';
import Button from 'Components/Forms/Button';
import { connect } from 'react-redux';
import { gql, useMutation } from '#apollo/client';
import ReactTelInput from 'react-telephone-input';
const formName = 'PhoneVerifyForm';
const performPhoneVerificationMutation = gql`
mutation registerPage_userPhoneVerification($input: RegisterPhoneVerificationInput!) {
userPhoneVerification(input: $input) {
errors {
field
messages
}
phoneNumberVerificationSid
verified
}
}
`;
// TODO props: unconfirmedUserId, phoneNumberVerificationSid, initialValues, callback
const PhoneVerifyForm = (props) => {
const [editPhoneEnabled, setEditPhoneEnabled] = useState(false);
const [codeSend, setCodeSend] = useState(props.phoneNumberVerificationSid !== undefined);
const [performPhoneVerification, { data:performPhoneVerificationData }] = useMutation(performPhoneVerificationMutation);
const [errors, setErrors] = useState([]);
useEffect(() => {
if (performPhoneVerificationData && performPhoneVerificationData.userPhoneVerification) {
const {userPhoneVerification} = performPhoneVerificationData;
if(userPhoneVerification.errors.length === 0) {
setErrors([])
if (editPhoneEnabled) {
editPhoneEnabled(false);
}
setCodeSend(userPhoneVerification.phoneNumberVerificationSid !== undefined);
if(userPhoneVerification.verified !== undefined) {
props.callback(props.formValues.phone);
}
} else {
setErrors(userPhoneVerification.errors)
}
}
}, [performPhoneVerificationData, ])
function handleSubmit(values) {
if (editPhoneEnabled) {
// update phone number
return performPhoneVerification({
variables: {
input: {
unconfirmedUserId: props.unconfirmedUserId,
phone: values.phoneNumber,
},
},
});
} else if (!codeSend) {
// send new code
return performPhoneVerification({
variables: {
input: {
unconfirmedUserId: props.unconfirmedUserId,
channel: values.channel,
},
},
});
}
// else validate code
return performPhoneVerification({
variables: {
input: {
unconfirmedUserId: props.unconfirmedUserId,
code: values.code,
},
},
});
}
const handleEditPhone = () => {
setEditPhoneEnabled(!editPhoneEnabled);
setCodeSend(false);
};
const phoneFieldRenderer = ({ input }) => {
return (
<ReactTelInput {...input} />
)
}
return (
<form className="row" onSubmit={props.handleSubmit(handleSubmit)}>
{!codeSend && <Col style={{background: 'pink'}}>
<p>{t('select channel')}</p>
<FormGroup row className="indented-form-group">
<Col>
<label>
<Field
name="channel"
component="input"
type="radio"
value="sms"
validate={Validator.required}
/>
{t('Sms')}
</label>
</Col>
<Col xs={6}>
<label>
<Field
name="channel"
component="input"
type="radio"
value="phone"
validate={Validator.required}
/>
{t('phone')}
</label>
</Col>
</FormGroup>
</Col>}
{codeSend && <Col style={{background: 'yellow'}}>
<FormGroup row className="indented-form-group">
<Field
labelClassname="required"
label={t('Code')}
name="code"
component="input"
type="text"
validate={[Validator.required]}
/>
</FormGroup>
</Col>}
<Col style={{background: 'red'}}>
<FormGroup row className="indented-form-group">
{!editPhoneEnabled && <div>
<span>PHONE PLACEHOLDER</span><br />
<span onClick={handleEditPhone}>Edit phone number</span>
</div>}
{editPhoneEnabled && <Field
name="phoneNumber"
component={phoneFieldRenderer}
validate={[Validator.required, Validator.phone]}
/>}
</FormGroup>
</Col>
<Col>
<FormGroup row className="indented-form-group">
<Button submit disabled={props.submitting || props.invalid}>
{editPhoneEnabled ? t('Change phone number') : codeSend ? t('Validate code') : t('Send code')}
</Button>
</FormGroup>
</Col>
</form>
);
};
const mapStateToProps = state => ({
formValues: getFormValues(formName)(state) || {}, //This basically gives us the form values in the props and it gets updated on keydown.
});
const decoratedComponent = connect(mapStateToProps, null)(PhoneVerifyForm)
export default (reduxForm({
form: formName,
enableReinitialize: true,
shouldAsyncValidate: ({ trigger }) => ['blur'].includes(trigger),
})(decoratedComponent));

GET request does not have latest entry inside

I made an Event Feed in React. Here is the structure (I've removed unrelated components:
App.js
|_EventFeed.js
|_EventCreate.js
My problem is this:
When I create an event in EventCreate, I hope for the EventFeed to update with the latest entry but it does not happen. It does update eventually after a few seconds or refreshes - and I think this delay is because I'm using free Heroku dynos on the back-end.
How can I make it update automatically?
Code here:
EventFeed.js
import React from 'react';
import {
Button,
Row,
Col,
CardBody,
CardSubtitle,
Container,
CardText,
CardTitle,
Progress,
} from 'reactstrap';
import axios from 'axios';
import Loader from '../images/loader.gif';
import { Link } from "react-router-dom";
import nightWorkout from "../images/nightWorkout.jpg";
class EventFeed extends React.Component {
constructor(props) {
super(props);
this.state = {
message: true,
eventsList: [],
isLoading: true,
eventsJoined:0
}
}
//retrieve all events via axios
componentDidMount() {
axios.get('https://final-project-healthy.herokuapp.com/api/v1/events/')
.then(response => {
let tempEventList = response.data;
this.setState({ eventsList: tempEventList, isLoading: false })
})
.catch(error => {
console.log('ERROR: ', error);
})
}
refreshFeed = () =>{
axios.get('https://final-project-healthy.herokuapp.com/api/v1/events/')
.then(response => {
let tempEventList = response.data;
this.setState({ eventsList: tempEventList, isLoading: false })
})
.catch(error => {
console.log('ERROR: ', error);
})
}
componentDidUpdate(){
this.refreshFeed();
}
handleSubmit = e =>{
//make an api call to guestlist and add or delete current user to guest list
let event_id = e.target.id
let JWT = localStorage.getItem('userToken')
axios.post('https://final-project-healthy.herokuapp.com/api/v1/guestlists/',
{event_id:event_id},
{
headers:{
Authorization: `Bearer ${JWT}`
}
}
).then(response => {
console.log(response);
this.refreshFeed();
}).catch(error => {
console.log("ERROR in request: ", error)
})
}
render() {
const { eventsList, isLoading } = this.state;
return (
<div style={{backgroundImage: `url(${nightWorkout})`, backgroundSize:'cover', backgroundAttachment:'fixed', height:'100wh'}}>
<div>
<h1 className="text-center text-light shadow">Events Near You</h1>
<h4 className="text-center text-light shadow">Don't see a fitness meet you like? How about <Link to={'/events/create'}>creating your own</Link>?</h4>
{isLoading ?
<Container>
<Row className="d-flex align-items-center justify-content-center">
<img src={Loader} alt="Loading event feed" />
</Row>
</Container>
:
eventsList.map((eventInList) => {
let guestlist=[]
if (eventInList.guests.includes(this.props.current_user.id)){
console.log('The user is here!')
}
return (
<Container key={eventInList.id} className="my-2 bg-none">
<Row md="10" className="d-flex align-items-center rounded bg-info" style={{opacity:'0.9'}}>
<Col md="4" className=" d-flex justify-content-center align-item-center rounded">
<img width="200px" height="200px" className="border border-white m-3 rounded justify-content-center" src={eventInList.image} alt="event image" />
</Col>
<Col md="8" className="rounded">
<CardBody className="p-1 text-left">
<CardTitle><h3 className='text-light'>{eventInList.name}</h3></CardTitle>
<CardSubtitle className='text-light'>{eventInList.time}</CardSubtitle>
<CardText className='text-light'>Host : {eventInList.host.username}</CardText>
<CardText className='text-light'>Location:{eventInList.location}<br/>What to expect:{eventInList.description}</CardText>
<CardText className="text-light">Capacity: {eventInList.guests.length}/{eventInList.max_number}</CardText>
<Row className="align-items-center">
<Col md="8">
<Progress color="success" value={Math.floor(eventInList.guests.length/eventInList.max_number*100)} />
</Col>
<Col md="4">
{eventInList.guests.includes(this.props.current_user.id)
?
<Button id={eventInList.id} color="danger" onClick={this.handleSubmit}>Leave</Button>
:
<Button id={eventInList.id} color="success" onClick={this.handleSubmit}>Join</Button>
}
</Col>
</Row>
</CardBody>
</Col>
</Row>
</Container>)
})
}
</div>
</div>
)
}
}
export default EventFeed;
EventCreate.js
import React from 'react';
import {
Card,
CardImg,
CardText,
Button,
Col,
Form,
FormText,
FormGroup,
Input,
Label,
Row,
} from "reactstrap"
import axios from 'axios';
import PlacesWithStandaloneSearchBox from "../components/PlacesWithStandaloneSearchBox";
import { Link } from "react-router-dom";
import Loader from "../images/loader.gif";
import morningRun from "../images/morning_run.jpg"
class EventCreate extends React.Component {
constructor(props) {
super(props);
this.imageUpload=React.createRef();
this.state = {
eventName: '',
description: '',
location: '',
time: '',
maxNumber: '',
isLoading:false,
previewImage:null,
imageFile:null,
message:''
}
}
handleChange = e => {
this.setState({ [e.target.id]: e.target.value }, () => {
//for debugging purposes, this ensures that the state is updated with the field values
for (const key in this.state) {
if (this.state.hasOwnProperty(key)) {
console.log(key + " -> " + this.state[key] + ` of data type ${typeof (this.state[key])}`);
}
}
})
console.clear()
}
liftMyLocationUp = locationFromGoogle => {
this.setState({ location: locationFromGoogle })
}
//handleSubmit lifts up field values
handleSubmit = (e) => {
let formData = new FormData()
formData.append("image_file", this.state.imageFile, this.state.imageFile.name);
formData.append("name", this.state.eventName);
formData.append("description", this.state.description);
formData.append("max_number", this.state.maxNumber);
formData.append("time", this.state.time);
formData.append("location", this.state.location);
console.log('handleSubmit called')
this.registerEvent(formData);
setTimeout(() => this.props.history.push('/events'), 2000);
}
handleFile = (e) =>{
console.log(e.target.files[0])
this.setState({
imageFile:e.target.files[0],
previewImage:URL.createObjectURL(e.target.files[0]),
})
}
//necessary to setState? why not just keep it as props or make ?
registerEvent = (formData) => {
let JWT = localStorage.getItem('userToken')
axios.post('https://final-project-healthy.herokuapp.com/api/v1/events/',
formData,
{
headers: {
'Authorization': `Bearer ${JWT}`
}
}
).then(response => {
if (response.data.success){
console.log(response.data.success)
}
}).catch(error => {
console.log("ERROR in request: ", error);
})
}
handleClick = () =>{
this.imageUpload.current.click();
}
render() {
const { event_name, description, location, max_number, time, isLoading, previewImage, imageFile, message } = this.state
return (
<div style={{backgroundImage: `url(${morningRun})`, backgroundSize:'cover', height:'100vh'}}>
<h3 className="text-center text-light">Create Your Event Here:</h3>
<Row className="d-flex justify-content-center">
<Col lg="4" md="5" sm="12" className="d-flex justify-content-center">
<Form className="d-flex justify-content-center">
<FormGroup >
<Label for="eventName" className="text-light">Event Name:</Label>
<Input id="eventName" type="text" value={event_name} onChange={this.handleChange} placeholder="Give me a name"></Input>
<Label for="description" className="text-light">Description:</Label>
<Input id="description" type="text" value={description} onChange={this.handleChange} placeholder="Share what I'm about"></Input>
<Label for="location" className="text-light">Location:</Label>
<PlacesWithStandaloneSearchBox liftMyLocationUp={this.liftMyLocationUp} />
{/* <Input id="location" type="text" value={location} onChange={this.handleChange} placeholder="Tell folks where to find me"></Input> */}
<Label for="time" className="text-light">Time:</Label>
<Input id="time" type="datetime-local" value={time} onChange={this.handleChange}></Input>
<Label for="maxNumber" className="text-light">Max Number:</Label>
<Input id="maxNumber" type="number" min="0" value={max_number} onChange={this.handleChange} placeholder="It's always better with company"></Input>
<div> </div>
</FormGroup>
</Form>
</Col>
<Col lg="4" md="5" sm="12" className="d-flex justify-content-center">
<Row>
<Form>
<FormGroup>
<Label className="d-block text-light">Upload your event image here:</Label>
<div id="image-preview" onClick={this.handleClick}>
<Card style={{width:"300px", height:"300px"}} className="d-flex justify-content-center align-items-center">
{/* Set loading icon when uploading picture. nested ternary operator. */}
{!isLoading?(!imageFile?(<h4 className="text-center">{message ? message : "Click to upload"}</h4>):(<CardImg src={previewImage} height="300px" width="300px"/>)):<Loader/>}
</Card>
</div>
<input id="upload" style={{display:"none"}} type="file" accept="image/*" multiple={false} name="image-file" ref={this.imageUpload} id="imageFile" onChange={this.handleFile}></input>
</FormGroup>
<FormGroup>
<div id="image-submit-form">
<Row >
<Col md={12} sm={12}>
</Col>
</Row>
</div>
</FormGroup>
</Form>
</Row>
</Col>
</Row>
<Row>
<Col className="d-flex justify-content-center">
<Button color="primary" className="text-light" onClick={this.handleSubmit}>Create Event</Button>
</Col>
</Row>
</div>
)
}
}
export default EventCreate;

How do I clear an array in the state of my Redux store?

I am building a small e-commerce shop and I am trying to clear my cart after a successful checkout. The cart contains cartItems which are stored in the Redux store. I am getting the console log in my function in the StripeCheckoutForm component and the action creator.
I am not seeing the console log for the reducer so I suspect something is wrong with my action creator. I am not sure about best practices concerning action creators. I was wondering when, why, and how to use dispatch in the action creator. The docs for Redux aren't exactly clear for me.
Here is my StripeCheckout:
import React, {Component} from 'react';
import { CardElement, injectStripe } from 'react-stripe-elements';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { clearCart } from '../actions/clearCartAction';
import getTotal from '../helpers/getTotalHelper';
import { Container, Col, Form, FormGroup, Input } from 'reactstrap';
import './StripeCheckoutForm.css';
const cardElement = {
base: {
color: '#32325d',
width: '50%',
lineHeight: '30px',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '18px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
const FIREBASE_FUNCTION = 'https://us-central1-velo-velo.cloudfunctions.net/charge/';
// Function used by all three methods to send the charge data to your Firebase function
async function charge(token, amount, currency) {
const res = await fetch(FIREBASE_FUNCTION, {
method: 'POST',
body: JSON.stringify({
token,
charge: {
amount,
currency,
},
}),
});
const data = await res.json();
data.body = JSON.parse(data.body);
return data;
}
class CheckoutForm extends Component {
constructor(props) {
super(props);
this.submit = this.submit.bind(this);
}
state = {
complete: false
}
clearCartHandler = () => {
console.log('clearCartHandler');
this.props.onClearCart()
}
// User clicked submit
async submit(ev) {
console.log("clicked!")
const {token} = await this.props.stripe.createToken({name: "Name"});
const total = getTotal(this.props.cartItems);
const amount = total; // TODO: replace with form data
const currency = 'USD';
const response = await charge(token, amount, currency);
if (response.statusCode === 200) {
this.setState({complete: true});
console.log('200!!',response);
this.clearCartHandler();
} else {
alert("wrong credit information")
console.error("error: ", response);
}
}
render() {
if (this.state.complete) {
return (
<div>
<h1 className="purchase-complete">Purchase Complete</h1>
<Link to='/'>
<button>Continue Shopping</button>
</Link>
</div>
);
}
return (
<div className="checkout-wrapper">
<Container className="App">
<h2 className='text-center'>Let's Checkout</h2>
<Form className="form">
<Col>
<FormGroup>
<Input
type="first name"
name="first name"
id="exampleEmail"
placeholder="first name"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="last name"
name="last name"
id="exampleEmail"
placeholder="last name"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="address"
name="address"
id="exampleEmail"
placeholder="address"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="city"
name="city"
id="exampleEmail"
placeholder="city"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="prefecture"
name="prefecture"
id="exampleEmail"
placeholder="prefecture"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="zipcode"
name="zipcode"
id="exampleEmail"
placeholder="zipcode"
/>
</FormGroup>
</Col>
<Col>
<FormGroup>
<Input
type="email"
name="email"
id="exampleEmail"
placeholder="myemail#email.com"
/>
</FormGroup>
</Col>
<div className="card-element">
<CardElement style={cardElement}/>
</div>
</Form>
<button className="checkout-button" disabled={false} onClick={this.submit}>Submit</button>
</Container>
</div>
);
}
}
const mapStateToProps = state => {
return {
cartItems: state.shoppingCart.cartItems
}
}
const mapDispatchToProps = state => {
return {
onClearCart: () => (clearCart())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(injectStripe(CheckoutForm));
Here is my action creator:
import { CLEAR_CART } from './types';
// export const clearCart = (dispatch) => {
// console.log('clear_action')
// dispatch({
// type: CLEAR_CART,
// })
// }
export function clearCart() {
console.log('clear_action')
return {
type: CLEAR_CART
}
}
and finally my reducer:
import {ADD_TO_CART} from '../actions/types';
import {REMOVE_FROM_CART} from '../actions/types';
import {CLEAR_CART} from '../actions/types';
const initialState = {
cartItems: [],
}
export default function(state = initialState, action) {
switch(action.type) {
case ADD_TO_CART:
console.log('ADD_reducer');
return {
...state,
cartItems: [...state.cartItems, action.payload],
}
case REMOVE_FROM_CART:
console.log('REMOVE_REDUCER', action.payload, state.cartItems);
return {
...state,
cartItems: state.cartItems.filter(item => item.id !== action.payload.id)
}
case CLEAR_CART:
console.log('CLEAR_REDUCER');
return {
...state,
cartItems: []
}
default:
return state;
}
}
Action has to be dispatched like below. Let me know if it works
const mapDispatchToProps = (dispatch) => {
return {
onClearCart: () => (dispatch(clearCart()))
}
};

Redux-form -- Initialize From State error and integrating to actions to post the data?

I am very new to redux-form - and I am trying to now grasp prefilled data concepts here.
http://redux-form.com/6.0.0-rc.1/examples/initializeFromState/
When I test this code - it breaks.
"TypeError: Cannot read property 'data' of undefined"
Also the way the example has written the connection/redux parts is different to how I've defined it in the past with other componomnents.
// Decorate with reduxForm(). It will read the initialValues prop provided by connect()
InitializeFromStateForm = reduxForm({
form: 'initializeFromState' // a unique identifier for this form
})(InitializeFromStateForm)
// You have to connect() to any reducers that you wish to connect to yourself
InitializeFromStateForm = connect(
state => ({
initialValues: state.account.data // pull initial values from account reducer
}),
{ load: loadAccount } // bind account loading action creator
)(InitializeFromStateForm)
export default InitializeFromStateForm
--
so other forms I have working - look like this.
// EditUserForm.js
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Row, Col } from 'antd';
import renderField from '../_SharedFormComponents/renderField'
import validate from './validateEditUser'
import warn from './warnEditUser'
const EditUserForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Row>
<Col xs={24} sm={24} md={12}>
<Field name="firstName" type="text" component={renderField} label="First Name" />
</Col>
<Col xs={24} sm={24} md={12}>
<Field name="lastName" type="text" component={renderField} label="Last Name" />
</Col>
</Row>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'syncValidationEditUser', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(EditUserForm)
^ then I have a shell parent.
//EditProfile.js
import React, { Component } from 'react'
import { withRouter, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchEditProfile } from '../../actions/editProfileAction';
import { Row, Col, Button, Tabs } from 'antd';
// components
import EditUserForm from './EditUserForm'
// this is a class because it needs state
class EditProfile extends Component {
constructor(props, context) {
super(props, context);
this.submitEditProfile = this.submitEditProfile.bind(this);
}
componentDidMount() {
// console.log('this', this)
}
submitEditProfile(data) {
this.props.fetchEditProfile(data);
}
render() {
return (
<div>
<div className="form-components light">
<Row>
<Col xs={24} sm={24} md={10}>
<p>Edit Profile</p>
</Col>
<Col xs={24} sm={24} md={24}>
<Row>
<Col xs={24} sm={24} md={24}>
<EditUserForm onSubmit={this.submitEditProfile} />
</Col>
</Row>
</Col>
</Row>
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
editProfileData: state.editProfile
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchEditProfile}, dispatch);
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))
--
so from my understanding here the way they have written the connect aspect in that demo is like this?
function mapStateToProps(state) {
return {
initialValues: state.account.data
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ load: loadAccount }, dispatch);
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))
--
but I still want to retain collecting and processing the data so ...
function mapStateToProps(state) {
return {
initialValues: state.initProfile,
editProfileData: state.editProfile
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchInitProfile, fetchEditProfile}, dispatch);
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))
and to invoke inside "compentDidMount Or compentWillMount or componentDidUpdate"? this.fetchInitProfile();
..
would my initProfile action would look like this?
//InitProfile.js
import axios from 'axios';
export const FETCH_INIT_PROFILE_SUCCESS = 'FETCH_INIT_PROFILE_SUCCESS'
export const FETCH_INIT_PROFILE_FAILURE = 'FETCH_INIT_PROFILE_FAILURE'
export function initProfileSuccess(response) {
return {
type: FETCH_INIT_PROFILE_SUCCESS,
payload: response
}
}
export function initProfileFail(response) {
return {
type: FETCH_INIT_PROFILE_FAILURE,
payload: response
}
}
export function fetchInitProfile(data) {
let url = 'https://api.github.com/users/theoldcounty';
return function (dispatch) {
axios.get(url)
.then(function (response) {
//console.log(response);
dispatch(initProfileSuccess(response));
})
.catch(function (error) {
//console.log(error);
dispatch(initProfileFail(error));
});
}
}
Here is the solution for making a form -- that will have initialValues - and then be able to make a call to stash the data.
Enjoy.
//EditProfile.js -- call this the shell --
import React, { Component } from 'react'
import { withRouter, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchEditProfile } from '../../actions/editProfileAction';
import { fetchInitProfile } from '../../actions/initProfileAction';
import { Row, Col, Button, Tabs } from 'antd';
// components
import EditUserSyncValidationForm from './EditUserSyncValidationForm'
// this is a class because it needs state
class EditProfile extends Component {
constructor(props, context) {
super(props, context);
this.submitEditProfile = this.submitEditProfile.bind(this);
this.props.fetchInitProfile(null);//maybe you will send data like the user id here or it may be stored on server side already if they have logged in
}
submitEditProfile(data) {
this.props.fetchEditProfile(data);
}
render() {
const initialValues = this.props.initProfileData.data;
return (
<div>
<div className="form-components light">
<Row>
<Col xs={24} sm={24} md={10}>
<p>Edit Profile</p>
</Col>
<Col xs={24} sm={24} md={24}>
<Row>
<Col xs={24} sm={24} md={24}>
<EditUserSyncValidationForm initialValues={initialValues} onSubmit={this.submitEditProfile} />
</Col>
</Row>
</Col>
</Row>
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
editProfileData: state.editProfile,
initProfileData: state.initProfile
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({fetchInitProfile, fetchEditProfile}, dispatch);
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))
//EditUserSyncValidation -- this is the form itself
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Row, Col } from 'antd';
import renderField from '../_SharedFormComponents/renderField'
import validate from './validateEditUser'
import warn from './warnEditUser'
const EditUserSyncValidationForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Row>
<Col xs={24} sm={24} md={12}>
<Field name="firstName" type="text" component={renderField} label="First Name" />
</Col>
<Col xs={24} sm={24} md={12}>
<Field name="lastName" type="text" component={renderField} label="Last Name" />
</Col>
</Row>
<Row>
<Col xs={24} sm={24} md={12}>
<Field name="pin" type="text" component={renderField} label="Pin" />
</Col>
<Col xs={24} sm={24} md={12}>
<Field name="email" type="email" component={renderField} label="Email" />
</Col>
</Row>
<Row>
<Col xs={24} sm={24} md={12}>
<Field name="password" type="password" component={renderField} label="Password" />
</Col>
<Col xs={24} sm={24} md={12}>
<Field name="confirmPassword" type="password" component={renderField} label="Confirm Password" />
</Col>
</Row>
<Row>
<Col xs={24} sm={24} md={12}>
<Field name="phoneNumber" type="text" component={renderField} label="Phone Number" />
</Col>
<Col xs={24} sm={24} md={12}>
</Col>
</Row>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'syncValidationEditUser', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(EditUserSyncValidationForm)
then we have actions.
//editProfileAction.js
import axios from 'axios';
export const FETCH_EDIT_PROFILE_SUCCESS = 'FETCH_EDIT_PROFILE_SUCCESS'
export const FETCH_EDIT_PROFILE_FAILURE = 'FETCH_EDIT_PROFILE_FAILURE'
export function editProfileSuccess(response) {
return {
type: FETCH_EDIT_PROFILE_SUCCESS,
payload: response
}
}
export function editProfileFail(response) {
return {
type: FETCH_EDIT_PROFILE_FAILURE,
payload: response
}
}
export function fetchEditProfile(data) {
let url = '/apicall/editUser';
return function (dispatch) {
axios.get(url)
.then(function (response) {
//console.log(response);
dispatch(editProfileSuccess(response));
})
.catch(function (error) {
//console.log(error);
dispatch(editProfileFail(error));
});
}
}
//initProfileAction.js
import axios from 'axios';
export const FETCH_INIT_PROFILE_SUCCESS = 'FETCH_INIT_PROFILE_SUCCESS'
export const FETCH_INIT_PROFILE_FAILURE = 'FETCH_INIT_PROFILE_FAILURE'
export function initProfileSuccess(response) {
return {
type: FETCH_INIT_PROFILE_SUCCESS,
payload: response
}
}
export function initProfileFail(response) {
return {
type: FETCH_INIT_PROFILE_FAILURE,
payload: response
}
}
export function fetchInitProfile(data) {
let url = 'api/getInitialProfileData';
return function (dispatch) {
axios.get(url)
.then(function (response) {
//console.log(response);
var response = {
"firstName": "Johnny",
"lastName" : "Rockstar",
"pin" : "1234",
"email" : "johnny#bmail.com",
"phoneNumber" : "0202 02002020"
}
dispatch(initProfileSuccess(response));
})
.catch(function (error) {
//console.log(error);
dispatch(initProfileFail(error));
});
}
}
... then the reducers
//initProfileReducer.js
import { FETCH_INIT_PROFILE_SUCCESS, FETCH_INIT_PROFILE_FAILURE } from '../actions/initProfileAction'
export function initProfileReducer (state = {}, action) {
//console.log('reducer REG act', action)
switch (action.type) {
case FETCH_INIT_PROFILE_SUCCESS:
return {...state, data: action.payload, isProfileInit: true};
case FETCH_INIT_PROFILE_FAILURE:
return {...state, data: action.payload, isProfileInit: false};
default:
return {...state}
}
}
//editProfileReducer.js
import { FETCH_EDIT_PROFILE_SUCCESS, FETCH_EDIT_PROFILE_FAILURE } from '../actions/editProfileAction'
export function editProfileReducer (state = {}, action) {
switch (action.type) {
case FETCH_EDIT_PROFILE_SUCCESS:
return {...state, data: action.payload, isProfileEdited: true};
case FETCH_EDIT_PROFILE_FAILURE:
return {...state, data: action.payload, isProfileEdited: false};
default:
return {...state}
}
}

Resources