I'm using Django and React to make a YouTube clone.
I tried to post the video on the frontend side, and got an error in terminal:
<QueryDict: {'title': ['Test Video Creation'], 'user': ['1'], 'description': ['Is it working?'], 'image': [<TemporaryUploadedFile: attachment.png (image/png)>], 'video': [<TemporaryUploadedFile: video-for-fatube.mp4 (video/mp4)>]}>Bad Request: /api/admin/create/
And the problem is not in the backend settings, because when I made a post request in the postman, the video was succesfully created.
creat.js File on frontend side to create videos.
import React, { useState } from 'react';
import axiosInstance from '../../axios';
import { useHistory } from 'react-router-dom';
//MaterialUI
import Avatar from '#material-ui/core/Avatar';
import axios from "axios";
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import { makeStyles } from '#material-ui/core/styles';
import Container from '#material-ui/core/Container';
import IconButton from '#material-ui/core/IconButton';
import PhotoCamera from '#material-ui/icons/PhotoCamera';
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function Create() {
const history = useHistory();
const initialFormData = Object.freeze({
title: '',
description: '',
});
const [videoData, updateFormData] = useState(initialFormData);
const [videoimage, setVideoImage] = useState(null);
const [videovideo, setVideoVideo] = useState(null);
const handleChange = (e) => {
if ([e.target.name] == 'image') {
setVideoImage({
image: e.target.files,
});
console.log(e.target.files);
}
if ([e.target.name] == 'video') {
setVideoVideo({
video: e.target.files,
});
console.log(e.target.files);
}
if ([e.target.name] == 'title') {
updateFormData({
...videoData,
[e.target.name]: e.target.value.trim(),
});
} else {
updateFormData({
...videoData,
[e.target.name]: e.target.value.trim(),
});
}
};
const handleSubmit = (e) => {
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
const URL = 'http://127.0.0.1:8000/api/admin/create/';
let formData = new FormData();
formData.append('title', videoData.title);
formData.append('user', 1);
formData.append('description', videoData.description);
formData.append('image', videoimage.image[0]);
formData.append('video', videovideo.video[0]);
axios
.post(URL, formData, config)
.then((res) => {
console.log(res.data);
})
.catch((err) => console.log(err));
};
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}></Avatar>
<Typography component="h1" variant="h5">
Create New Video
</Typography>
<form className={classes.form} noValidate>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="title"
label="Video Title"
name="title"
autoComplete="title"
onChange={handleChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="description"
label="Video Description"
name="description"
autoComplete="description"
onChange={handleChange}
multiline
rows={4}
/>
</Grid>
<input
accept="image/*"
className={classes.input}
id="video-image"
onChange={handleChange}
name="image"
type="file"
/>
<input
accept="video/*"
className={classes.input}
id="video-video"
onChange={handleChange}
name="video"
type="file"
/>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={handleSubmit}
>
Create Video
</Button>
</form>
</div>
</Container>
);
}
If you want to look at the whole project, here is Github: https://github.com/PHILLyaHI/diplom-work
What I did to make it work is I deleted files in the media folder and deleted all the videos.
Related
I am new to stripe and APIs and followed a tutorial to implement stripe checkout and implemented that successfully but I want to display a receipt after stripe checkout.
Do you know any such tutorial or can anyone please help.
Also, after the payment, in the stripe dashboard I am getting status as incomplete and it says that three_d_secure authentication is required which I had turned on in the setting but whenever I enter card details it never asks. Would like to learn that too. Let me know if there are any good resources for the same. Would be grateful to have someone guideme.
Code for listening on port 4000
const express = require("express")
const app = express()
require("dotenv").config()
const stripe = require("stripe")(process.env.STRIPE_SECRET_TEST)
const bodyParser = require("body-parser")
const cors = require("cors")
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use(cors())
app.post("/payment", cors(), async (req, res) => {
let { amount, id } = req.body
try {
const payment = await stripe.paymentIntents.create({
amount,
currency: "USD",
description: "pay",
payment_method: id,
confirm: true
})
console.log("Payment", payment)
res.json({
message: "Payment successful",
success: true
})
} catch (error) {
console.log("Error", error)
res.json({
message: "Payment failed",
success: false
})
}
})
app.listen(process.env.PORT || 4000, () => {
console.log("Sever is listening on port 4000")
})
code for checkout form
import { CardElement, useElements, useStripe } from "#stripe/react-stripe-js"
import { CardNumberElement, CardExpiryElement, CardCvcElement } from "#stripe/react-stripe-js";
import {ArrowForward } from '#material-ui/icons';
import axios from "axios"
import React, { useState } from 'react'
import './styles.css';
import { DataGrid } from "#material-ui/data-grid";
import { Typography } from "#material-ui/core";
import { Alert } from "#material-ui/core";
import { LoadingButton } from "#material-ui/lab";
import {Button, TextField, Paper, Grid } from "#material-ui/core";
import StripeInput from "../../src/components/StripeInput";
const CARD_OPTIONS = {
iconStyle: "solid",
style: {
base: {
iconColor: "#c4f0ff",
color: "#fff",
fontWeight: 500,
fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
fontSize: "16px",
fontSmoothing: "antialiased",
":-webkit-autofill": { color: "#fce883" },
"::placeholder": { color: "#87bbfd" }
},
invalid: {
iconColor: "#ffc7ee",
color: "#ffc7ee"
}
}
}
export default function PaymentForm() {
const [success, setSuccess ] = useState(false)
const stripe = useStripe()
const elements = useElements()
const [loading, setLoading] = React.useState(false);
const handleSubmit = async (e) => {
setLoading(true);
e.preventDefault()
const {error, paymentMethod} = await stripe.createPaymentMethod({
type: "card",
card: elements.getElement(CardNumberElement)
})
if(!error) {
try {
const {id} = paymentMethod
const response = await axios.post("http://localhost:4000/payment", {
amount: 1000,
id
})
if(response.data.success) {
console.log("Successful payment")
setSuccess(true)
}
} catch (error) {
console.log("Error", error)
}
} else {
console.log(error.message)
}
}
const paperStyle={padding:'30px 20px', width: 600, margin: "20px auto"}
const marginTop = { marginTop: 10}
return (
<center>
<>
{!success ?
<div>
<Grid>
<Paper elevation ={20} style = {paperStyle} >
<Grid align='center'></Grid>
<form>
<Grid item xs ={12}></Grid>
<Grid item xs={12} sm={6}>
<TextField
//placeholder="XXXX XXXX XXXX XXXX"
label="Card Number"
style={marginTop}
fullWidth
InputLabelProps={{
shrink: true,
}}
InputProps={{
inputComponent: StripeInput,
inputProps: {
component: CardNumberElement
},
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
//placeholder="MM/YY"
fullWidth
label="Expiry Date"
style={marginTop}
InputLabelProps={{
shrink: true,
}}
InputProps={{
inputComponent: StripeInput,
inputProps: {
component: CardExpiryElement
},
}}
/>
</Grid>
<Grid item xs ={12}></Grid>
<Grid item xs={12} sm={6}>
<TextField
//placeholder="XXX"
fullWidth
label="CVV"
style={marginTop}
InputLabelProps={{
shrink: true,
}}
InputProps={{
inputComponent: StripeInput,
inputProps: {
component: CardCvcElement
},
}}
/>
</Grid>
<Grid item xs ={12}></Grid>
<Grid item xs={12} sm={6}>
<LoadingButton
loading ={loading}
loadingPosition="start"
startIcon={<ArrowForward />}
fullWidth
variant="outlined"
onClick={handleSubmit}
style={marginTop}>
Pay
</LoadingButton>
</Grid>
</form>
</Paper>
</Grid>
<center>
</center>
</div>
:
<Grid>
<Paper elevation ={20} style = {paperStyle} >
<Grid align='center'></Grid>
<Alert severity="success">
Your payment is Successful. Thanks for using our service.
</Alert>
</Paper>
</Grid>
}
</>
</center>
)
}
You can learn about sending receipts from Stripe on successful payment or refunds here
To your second question, use card no 4000 0025 0000 3155 to test 3D secure integration. Read more here
I'm using Material UI's "Dialog" component to open a separate mini-form upon a button click event. However, the Dialog box is actually opening up on page render. And I'm also unable to close it by clicking the box's "Cancel" button. Not to mention, whenever I attempt to type in anything into either of the Dialog box's textfields: my client crashes with an error of "TypeError: this.setState is not a function" for the line of: onChange={(e) => this.setState({ playlistName: e.target.value })}
import React, { Component } from 'react';
import { ThemeProvider } from '#material-ui/core';
import Grid from '#material-ui/core/Grid';
import Button from '#material-ui/core/Button';
import FormLabel from '#material-ui/core/FormLabel';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import TextField from '#material-ui/core/TextField';
import { makeStyles, withStyles } from '#material-ui/core/styles';
import { DataGrid } from '#material-ui/data-grid';
import Footer from './Footer';
import theme from '../../styles/MuiTheme';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemAvatar from '#material-ui/core/ListItemAvatar';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import FormGroup from '#material-ui/core/FormGroup';
import Checkbox from '#material-ui/core/Checkbox'
import Typography from '#material-ui/core/Typography';
import DeleteIcon from '#material-ui/icons/Delete';
import EditIcon from '#material-ui/icons/Edit';
import ListItemSecondaryAction from '#material-ui/core/ListItemSecondaryAction';
import QueueMusicIcon from '#material-ui/icons/QueueMusic';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
const styles = theme => ({
root: {
flexGrow: 1,
'& > *': {
margin: theme.spacing(1),
width: '25ch',
maxWidth: 752
},
control: {
padding: theme.spacing(2)
},
button: {
primary: "#1DB954"
},
listAllPlaylists: {
backgroundColor: theme.palette.background.paper,
overflow: "auto",
maxHeight: "10"
},
title: {
margin: theme.spacing(4, 0, 2)
}
}
});
function generate(element) {
return [0].map((value) =>
React.cloneElement(element, {
key: value
}),
);
}
class EditPlaylistDetails extends Component {
constructor(props) {
super(props);
this.state = {
artist: '',
album: '',
song: '',
playlistName: '',
description: '',
playlistData: [],
allPlaylists: [],
open: false,
secondary: false
}
// this.displayExistingPlaylists = this.displayExistingPlaylists.bind(this);
// this.displayLivePlaylistData = this.displayLivePlaylistData.bind(this);
this.editModal = this.editModal.bind(this)
this.handlePlaylistDelete = this.handlePlaylistDelete.bind(this)
this.handlePlaylistEdit = this.handlePlaylistEdit.bind(this)
this.handleClickOpen = this.handleClickOpen.bind(this)
this.handleClose = this.handleClose.bind(this)
};
handleSecondary = () => {
this.setState({ secondary: true });
};
// handleDense = () => {
// this.setState({ dense: true });
// };
componentDidMount() {
fetch('http://localhost:5040/playlist/', {
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
}).then((response) => response.json())
.then((res) => {
console.log(res);
return res;
}).then((res) => {
this.setState({
allPlaylists: res,
playlistData: res
})
})
.catch((err) => { console.log(err) })
};
handlePlaylistDelete(playlistDeleteId, userId) {
console.log(playlistDeleteId)
fetch(`http://localhost:5040/playlist/delete/${playlistDeleteId}`, {
method: 'DELETE',
body: JSON.stringify({
playlist: {
playlistId: this.props.playlistIdProp,
playlistName: this.state.playlistName,
description: this.state.description
}
}),
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
})
.then(res => res.json())
.catch(err => console.log(err))
};
handlePlaylistEdit(playlistUpdateId) {
playlistUpdateId.preventDefault();
fetch(`http://localhost:5040/playlist/update/${playlistUpdateId}`, {
method: 'PUT',
body: JSON.stringify({
playlist: {
playlistId: this.props.playlistIdProp,
playlistName: this.state.playlistName,
description: this.state.description
}
}),
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': this.props.sessionToken
})
}).then(
(response) => response.json()
).then((allPlaylistsResponse) => {
console.log(this.state.open)
});
};
editModal(playlistId) {
return (
<div>
<form onSubmit={() => this.handlePlaylistEdit(playlistId)} noValidate autoComplete="off" style={{ marginTop: '2rem' }}>
<TextField size="small" id="outlined-basic standard-size-small" label="Artist / Band" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ artist: e.target.value })} value={this.state.artist} />
<TextField size="small" id="outlined-basic standard-size-small" label="Album" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ album: e.target.value })} value={this.state.album} />
<TextField size="small" id="outlined-basic standard-size-small" label="Song" variant="filled" style={{ backgroundColor: 'white', color: 'white', borderRadius: '10px' }} onChange={(e) => this.setState({ song: e.target.value })} value={this.state.song} />
<br />
<Button variant="contained" color="primary" type="submit">Add Info to Playlist</Button>
</form>
</div>
)
};
handleClickOpen() {
this.setState = ({
open: true
})
};
handleClose() {
this.setState = ({
open: false
})
};
render() {
const { classes } = this.props;
return (
<ThemeProvider theme={theme}>
<div style={{ width: '100%', marginTop: '80px' }}>
<h1>View / Edit Your Created Playlists:</h1>
{/* <div >
{this.displayExistingPlaylists()}
</div> */}
<Grid container direction="column" alignContent="center" spacing={2} className={this.props.classes.root}>
<Grid item xs={12} md={6}>
<div style={{ textAlign: "-webkit-center", maxHeight: 400, overflow: 'auto' }}>
{this.state.allPlaylists.map((allPlaylistsCreated, index) => {
console.log(this.state.allPlaylists)
console.log(allPlaylistsCreated)
const { classes } = this.props;
return (
<Grid key={index} item xs={12} md={6} style={{ maxHeight: '100px', overflow: 'auto', textAlign: "center" }}>
<div className={classes.listAllPlaylists}>
<List>
{generate(
<ListItem>
<ListItemAvatar>
<Avatar>
<QueueMusicIcon key={index} style={{ color: "#191414" }} />
</Avatar>
</ListItemAvatar>
<ListItemText
key={index}
primary={allPlaylistsCreated.playlistName}
secondary={allPlaylistsCreated.description}
style={{ color: "white" }}
/>
<ListItemSecondaryAction>
<IconButton edge="start" aria-label="edit">
<EditIcon key={index} style={{ color: "#1DB954" }} onClick={this.handleClickOpen(allPlaylistsCreated.id)} />
</IconButton>
<IconButton edge="end" aria-label="delete">
<DeleteIcon key={index} style={{ color: "red" }} onClick={() => this.handlePlaylistDelete(allPlaylistsCreated.id, allPlaylistsCreated.userId)} />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
)}
</List>
</div>
</Grid>
)
})}
</div>
</Grid>
</Grid>
<form onSubmit={this.handlePlaylistEdit}>
<Dialog open={this.handleClickOpen} onClose={this.handleClose}>
<DialogTitle>Update Playlist Details:</DialogTitle>
<DialogContent>
<DialogContentText>
You may update your playlist information below:
</DialogContentText>
<TextField
margin='dense'
id='playlistName'
label='Playlist Name:'
fullWidth
onChange={(e) => this.setState({ playlistName: e.target.value })}
value={this.state.playlistName}
required
/>
<br />
<TextField
margin='dense'
id='description'
label='Description:'
fullWidth
onChange={(e) => this.setState({ description: e.target.value })}
value={this.state.description}
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color='primary'>
Cancel
</Button>
<Button onClick={this.handlePlaylistEdit} color='primary'>
Update Playlist
</Button>
</DialogActions>
</Dialog>
</form>
</div>
</ThemeProvider >
)
}
}
export default withStyles(styles, { withTheme: true })(EditPlaylistDetails);
syntax is wrong for setState
handleClickOpen() {
this.setState ({
open: true
})
}
handleClose() {
this.setState({
open: false
})
}
also correct below open value binding to {this.state.open}
<Dialog open={this.state.open} .... />
You are passing something for handleClickOpen() method, but not accepting any parameter in function definition.
<EditIcon key={index} style={{ color: "#1DB954" }} onClick={this.handleClickOpen(**allPlaylistsCreated.id**)} />
import axios from 'axios'
import Copyright from '../components/Copyright'
// Material UI Stuff
import { makeStyles } from '#material-ui/core/styles'
import CircularProgress from '#material-ui/core/CircularProgress'
import Container from '#material-ui/core/Container'
import Typography from '#material-ui/core/Typography'
import TextField from '#material-ui/core/TextField'
import Button from '#material-ui/core/Button'
import Box from '#material-ui/core/Box'
const INITIAL_STATE = {
cohort: '',
program: '',
github: '',
website: '',
linkedIn: ''
}
const inputProps = {
step: 1,
min: 1,
max: 99
}
const Profile = () => {
const [formData, setFormData] = useState(INITIAL_STATE)
const [isloading, setIsLoading] = useState(false)
const [errors, setErrors] = useState({})
const [user, setUser] = useState(null)
const isInvalid = !formData.cohort || !formData.program || isloading
const handleInputChange = field => e => {
setFormData({ ...formData, [field]: e.target.value })
}
const fetchProfile = async () => {
const token = await localStorage.FBIdToken
await axios
.get(`/user`, {
headers: {
Authorization: `${token}`
}
})
.then(res => {
setUser(res.data)
setFormData({
...formData,
github: res.data.user.github ? res.data.user.github : '',
website: res.data.user.website ? res.data.user.website : '',
linkedIn: res.data.user.linkedIn ? res.data.user.linkedIn : '',
cohort: res.data.user.cohort,
program: res.data.user.program
})
})
.catch(err => console.log('*** WRONG ***'))
}
useEffect(() => {
fetchProfile()
}, [])
const handleSubmit = async e => {
e.preventDefault()
setIsLoading(true)
const fireToken = await localStorage.FBIdToken
await axios
.post(
(`/user`,
{
headers: {
Authorization: `${fireToken}`
}
})
)
.then(res => {
console.log(res.data)
setIsLoading(false)
})
.catch(err => {
console.log(err)
setIsLoading(false)
})
}
const useStyles = makeStyles(theme => ({
form: {
textAlign: 'center',
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
position: 'relative'
},
logo: {
width: 180,
height: 180,
display: 'block',
alignItems: 'center'
},
submit: {
margin: theme.spacing(3, 0, 2),
position: 'relative'
},
progress: {
position: 'absolute'
},
customError: {
color: 'red',
fontSize: '0.8rem',
width: '100%',
position: 'absolute'
}
}))
const classes = useStyles()
return (
<>
{user ? (
<div>
<Container component="main" maxWidth="xs">
<div className={classes.paper}>
<img
src={user.user.imageUrl}
alt="wyncode logo"
className={classes.logo}
/>
<Typography variant="h3" className={classes.pageTitle}>
Sign Up
</Typography>
<form noValidate onSubmit={handleSubmit} className={classes.form}>
<TextField
variant="outlined"
margin="normal"
fullWidth
id="website"
type="website"
label="Website"
name="website"
autoComplete="website"
value={formData.website}
onChange={handleInputChange('website')}
/>
<TextField
variant="outlined"
margin="normal"
fullWidth
id="cohort"
type="number"
inputProps={inputProps}
label="Cohort #"
name="cohort"
autoComplete="cohort"
helperText={errors.cohort}
error={errors.cohort ? true : false}
value={formData.cohort}
onChange={handleInputChange('cohort')}
/>
<TextField
variant="outlined"
margin="normal"
fullWidth
id="linkedIn"
type="linkedIn"
label="LinkedIn"
name="linkedIn"
autoComplete="linkedIn"
value={formData.linkedIn}
onChange={handleInputChange('linkedIn')}
/>
<TextField
variant="outlined"
margin="normal"
fullWidth
id="github"
type="github"
label="GitHub"
name="github"
autoComplete="github"
value={formData.github}
onChange={handleInputChange('github')}
/>
<TextField
variant="outlined"
margin="normal"
fullWidth
id="program"
type="program"
label="Program"
name="program"
helperText={errors.program}
error={errors.program ? true : false}
autoComplete="program"
value={formData.program}
onChange={handleInputChange('program')}
/>
{errors.general && (
<Typography variant="body2" className={classes.customError}>
{errors.general}
</Typography>
)}
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
disabled={isInvalid}
>
Update User Info
{isloading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
</div>
) : (
<CircularProgress size={60} className={classes.progressOne} />
)}
</>
)
}
export default Profile
I am fetching the token for my headers from local storage and trying to post the form data to my user endpoint. When I post, I get an error stating:
xhr.js:178 POST http://localhost:3000/[object%20Object] 404 (Not
Found)
I'm hitting the correct end point, but for some reason the post isn't hitting the /user endpoint with my form data. any insight would be awesome.
I am going through trouble to connectand dispatch in function based component. I know how to connect and dispatch class based component.
This is my code;
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
import Button from '#material-ui/core/Button';
import SaveIcon from '#material-ui/icons/Save';
import { connect } from "react-redux";
const useStyles = makeStyles(theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: 200,
},
dense: {
marginTop: 19,
},
menu: {
width: 200,
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
button: {
margin: theme.spacing(1),
},
}));
export default function TextFields() {
const classes = useStyles();
const [values, setValues] = React.useState({
ssn: '',
phone: '',
email: '',
multiline: 'Controlled',
});
const handleChange = name => event => {
setValues({ ...values, [name]: event.target.value });
};
const onSubmit = () => {
const data = {
ssn: values.ssn,
phone: values.phone,
email: values.email
}
console.log(data)
this.props.dispatch({type: 'SUBMIT', data})
}
return (
<React.Fragment>
<Grid item xs={12}>
<Paper className={classes.paper}>xs=12</Paper>
</Grid>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id=""
label="SSN"
value={values.ssn}
onChange={handleChange('ssn')}
type="number"
className={classes.textField}
name='ssn'
margin="normal"
/>
<TextField
id=""
label="Phone"
value={values.phone}
onChange={handleChange('phone')}
type="number"
className={classes.textField}
name='phone'
margin="normal"
/>
<TextField
id=""
label="Email"
value={values.email}
onChange={handleChange('email')}
type="email"
className={classes.textField}
margin="normal"
name='email'
/>
<Button
onClick={() => onSubmit()}
variant="contained"
color="primary"
size="small"
className={classes.button}
startIcon={<SaveIcon />}
>
Save
</Button>
</form>
</React.Fragment>
);
}
Can anyone help me to dispatch the data or connect ? THANKS IN ADVANCE
I am trying to create a sample login form in React using material-ui through graphql mutation. But the login form is not working as expected.
i am able to log in only some times, but even in those times, I do not see any data being passed via loginMutation props in console. Could some one please tell me what am i doing wrong here?
Here is the Login Component that I am trying to create
import React, { Component } from 'react';
import { AUTH_TOKEN } from '../constants';
import { graphql, compose } from 'react-apollo';
import {LOGIN_MUTATION} from "../gql/loginGQL";
import Paper from '#material-ui/core/Paper';
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField'
import PropTypes from 'prop-types';
import Avatar from '#material-ui/core/Avatar';
import CssBaseline from '#material-ui/core/CssBaseline';
import FormControl from '#material-ui/core/FormControl';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
//import Input from '#material-ui/core/Input';
//import InputLabel from '#material-ui/core/InputLabel';
import LockIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import withStyles from '#material-ui/core/styles/withStyles';
const styles = theme => ({
layout: {
width: 'auto',
display: 'block', // Fix IE11 issue.
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: {
width: 400,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing.unit * 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
},
avatar: {
margin: theme.spacing.unit,
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE11 issue.
marginTop: theme.spacing.unit,
},
submit: {
marginTop: theme.spacing.unit * 3,
},
});
class Login extends Component {
state = {
email: '',
password: '',
errors: null
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<LockIcon />
</Avatar>
<Typography variant="headline">Sign in</Typography>
<form className={classes.form}>
<FormControl margin="normal" required fullWidth>
<TextField
id='email'
value={this.state.email}
onChange={e => this.setState({ email: e.target.value })}
type='text'
label='Your email address'
/>
</FormControl>
<FormControl margin="normal" required fullWidth>
<TextField
id='password'
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type='password'
label='Password'
/>
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
id="submit"
type="submit"
fullWidth
variant="raised"
color="primary"
className={classes.submit}
onClick={() => this._confirm()}
>
Sign in
</Button>
</form>
</Paper>
</main>
</React.Fragment>
);
}
_confirm = async () => {
const { email, password } = this.state
try{
const result = await this.props.loginMutation({
variables: {
email,
password,
},
});
console.log(result); // Here no data is being displayed !
const { jwt } = result.data.signInUser;
this._saveUserData(jwt);
this.props.history.push(`/`)
} catch(error) {
const errors = error.graphQLErrors.map(error => error.message);
this.setState({ errors });
}
}
_saveUserData = (token) => {
localStorage.setItem(AUTH_TOKEN, token)
}
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
};
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
withStyles(styles),
)(Login)
The error was being occurred due to the Button tag. Although, it had type="submit", the form was still not being submitted due to which the input data was not being appearing in the "_confirm". I am wondering why, I must have missed something here.
For now, I created a div tag inside the Button and added onClick handler there instead of Button tag.
So, the edited code just have this small change
<Button color="primary" className = {classes.submit} variant="raised" fullWidth>
<div className="test" onClick={() => this._confirm()} >
Sign in
</div>
</Button>
Here is the full source code:
import React, { Component } from 'react';
import { AUTH_TOKEN } from '../constants';
import { graphql, compose } from 'react-apollo';
import {LOGIN_MUTATION} from "../gql/loginGQL";
import Paper from '#material-ui/core/Paper';
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField'
import PropTypes from 'prop-types';
import Avatar from '#material-ui/core/Avatar';
import CssBaseline from '#material-ui/core/CssBaseline';
import FormControl from '#material-ui/core/FormControl';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
//import Input from '#material-ui/core/Input';
//import InputLabel from '#material-ui/core/InputLabel';
import LockIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import withStyles from '#material-ui/core/styles/withStyles';
const styles = theme => ({
layout: {
width: 'auto',
display: 'block', // Fix IE11 issue.
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: {
width: 400,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing.unit * 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
},
avatar: {
margin: theme.spacing.unit,
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE11 issue.
marginTop: theme.spacing.unit,
},
submit: {
marginTop: theme.spacing.unit * 3,
},
});
class Login extends Component {
state = {
email: '',
password: '',
errors: null
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<LockIcon />
</Avatar>
<Typography variant="headline">Sign in</Typography>
<form className={classes.form}>
<FormControl margin="normal" required fullWidth>
<TextField
id='email'
value={this.state.email}
onChange={e => this.setState({ email: e.target.value })}
type='text'
label='Your email address'
/>
</FormControl>
<FormControl margin="normal" required fullWidth>
<TextField
id='password'
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type='password'
label='Password'
/>
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
// Here is the change
<Button color="primary" className = {classes.submit}
variant="raised"fullWidth >
<div className="test" onClick={() => this._confirm()} >
Sign in
</div>
</Button>
// Change ends here
</form>
</Paper>
</main>
</React.Fragment>
);
}
_confirm = async () => {
const { email, password } = this.state
try{
const result = await this.props.loginMutation({
variables: {
email,
password,
},
});
console.log(result); // Here no data is being displayed !
const { jwt } = result.data.signInUser;
this._saveUserData(jwt);
this.props.history.push(`/`)
} catch(error) {
const errors = error.graphQLErrors.map(error => error.message);
this.setState({ errors });
}
}
_saveUserData = (token) => {
localStorage.setItem(AUTH_TOKEN, token)
}
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
};
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
withStyles(styles),
)(Login)