Trouble with sending data from react to node - node.js

I'm trying to build a website where user post queries and other users are able to answer in it. I'm trying to implement various tags in it using react-tags-input module. However i'm having problem in sending those tags to node server. Help needed.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import '../Login.css';
import "./Home.css";
import Post from "./Post";
import { WithContext as ReactTags } from 'react-tag-input';
const KeyCodes = {
comma: 188,
enter: 13,
};
const delimiters = [KeyCodes.comma, KeyCodes.enter];
class query extends Component {
constructor() {
super();
this.state = {
userquery:'',
queries:[],
tags: [],
suggestions: [
{ id: "Javascript", text: "Javascript" },
{ id: "Java", text: "Java" },
{ id: 'node.js', text: 'node.js' },
{ id: 'react.js', text: 'react.js' },
{ id: 'express', text: 'express' },
{ id: 'bootstrap', text: 'bootstrap' },
{ id: 'python', text: 'python' },
{ id: 'c++', text: 'c++' }
]
};
this.handleDelete = this.handleDelete.bind(this);
this.handleAddition = this.handleAddition.bind(this);
this.handleDrag = this.handleDrag.bind(this);
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
componentDidMount(){
fetch('/query').
then((Response)=>Response.json()).
then(data =>{
this.setState({queries:data.reverse()});
})
}
handleDelete(i) {
const { tags } = this.state;
this.setState({
tags: tags.filter((tag, index) => index !== i),
});
}
handleAddition(tag) {
this.setState(state => ({ tags: [...state.tags, tag] }));
}
handleDrag(tag, currPos, newPos) {
const tags = [...this.state.tags];
const newTags = tags.slice();
newTags.splice(currPos, 1);
newTags.splice(newPos, 0, tag);
// re-render
this.setState({ tags: newTags });
}
render() {
const {userquery } = this.state;
const { tags, suggestions } = this.state;
return (
<div class="container">
<form action="/queries" method="POST">
<h2 class="form-signin-heading" color="blue">Want to ask something? ask here!</h2>
<label for="inputQuery" class="sr-only">query</label>
<textarea type="text" class="form-control" placeholder="want to ask something? ask here!" name="userquery" required/>
<br/>
<div class="form-group ">
<input class="form-control" type="text" name="image" placeholder="image url"/>
</div>
<div class="form-group ">
<ReactTags
name='tags'
tags={tags}
suggestions={suggestions}
handleDelete={this.handleDelete}
handleAddition={this.handleAddition}
handleDrag={this.handleDrag}
delimiters={delimiters}
/>
</div>
<br/>
<button class="btn btn-lg btn-primary btn-block" >Ask</button>
</form>
<section>
<h2> Recent Posts</h2>
</section>
{this.state.queries.map((item, key) => {
return (<Post item={item} key={key} />)
}
)
}
</div>
);
}
}
export default query;
server file - I'm able to get userquery and image but req.body.tags is returning an empty object.
app.post("/queries",isLoggedIn,function(req,res){
var postQuery =req.body.userquery;
var userImages =req.body.image;
console.log(req.body.tags);
username=req.user.username;
var newQuery = {
name:username,
image:userImages,
description:postQuery
}
Query.create(newQuery,function(err,newlyCreated){
if(err){
console.log(err);
}
else{
res.redirect("http://localhost:3000/home");
}
})
// res.send("you hit the post route")
});
Edited
onSubmit = e => {
e.preventDefault()
const {someText, tags} = this.state
const data = {someText, tags: tags.map(x => x.id)}
alert(`Submitting: ${JSON.stringify(data)}`)
fetch(
'queries',
{
method: 'POST',
mode: "cors", // no-cors, cors, *same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
},
)
}
server.js
app.post("/queries",function(req,res){
console.log("tags are:-",req.body)
});
output
tags are:- {}

The problem is in react-tags storing selected tags as a bunch of span elements, not input. So, these values are not included in form data being submitted.
You have to handle form submit logic manually.
Here is an example of handlers you need to add/change:
onSubmit = e => {
e.preventDefault() // stop default form submission
const { field1, field2, tags } = this.state // select form input values to submit
const data = { field1, field2, tags: tags.map(t => t.id) } // create an object to submit
fetch(
'url',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
},
) // send POST request
}
onChange = e => this.setState({ [e.target.name]: e.target.value }) // for plain inputs
onAdd = tag => this.setState(state => ({ tags: [...state.tags, tag] })) // for tags input
render() {
return (
<form onSubmit={this.onSubmit}>
<input name="field1" onChange={this.onChange} />
<input name="field2" onChange={this.onChange} />
<ReactTags
tags={this.state.tags}
handleAddition={this.onAdd}
/>
<button type="submit">submit</button>
</form>
)
}
Working example is in this sandbox.
Result is here: https://prnt.sc/kg2j9p
Update: now codesandbox uses fetch and posts the form data, you can try to submit form and see outgoing request in network tab in browser dev tools.

Related

Paypal payment failed with saved card

#SOLVED [from first comment answer]
I am try to build paypal advance payment and card save during payment with nodejs. I successfully build paypal advance payment and store card in vault. but the problem is while I try to pay with previously saved card, it fails. Order is created successfully then the error occurred.
checkout html (ejs)
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css" />
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=<%= clientId %>"
data-client-token="<%= clientToken %>"></script>
</head>
<body>
<div id="paypal-button-container" class="paypal-button-container"></div>
<div class="card_container">
<form id="card-form">
<label for="card-number">Card Number</label>
<div id="card-number" class="card_field"></div>
<div style="display: flex; flex-direction: row;">
<div>
<label for="expiration-date">Expiration Date</label>
<div id="expiration-date" class="card_field"></div>
</div>
<div style="margin-left: 10px;">
<label for="cvv">CVV</label>
<div id="cvv" class="card_field"></div>
</div>
</div>
<label for="card-holder-name">Name on Card</label>
<input type="text" id="card-holder-name" name="card-holder-name" autocomplete="off"
placeholder="card holder name" />
<div>
<label for="card-billing-address-street">Billing Address</label>
<input type="text" id="card-billing-address-street" name="card-billing-address-street" autocomplete="off"
placeholder="street address" />
</div>
<div>
<label for="card-billing-address-unit"> </label>
<input type="text" id="card-billing-address-unit" name="card-billing-address-unit" autocomplete="off"
placeholder="unit" />
</div>
<div>
<input type="text" id="card-billing-address-city" name="card-billing-address-city" autocomplete="off"
placeholder="city" />
</div>
<div>
<input type="text" id="card-billing-address-state" name="card-billing-address-state" autocomplete="off"
placeholder="state" />
</div>
<div>
<input type="text" id="card-billing-address-zip" name="card-billing-address-zip" autocomplete="off"
placeholder="zip / postal code" />
</div>
<div>
<input type="text" id="card-billing-address-country" name="card-billing-address-country" autocomplete="off"
placeholder="country code" />
</div>
<div>
<input type="checkbox" id="save" name="save">
<label for="save">Save your card</label>
</div>
<br /><br />
<button value="submit" id="submit" class="btn">Pay</button>
</form>
</div>
<script src="app.js"></script>
</body>
</html>
app.js
paypal
.Buttons({
// Sets up the transaction when a payment button is clicked
createOrder: function (data, actions) {
return fetch("/api/orders", {
method: "post"
// use the "body" param to optionally pass additional order information
// like product ids or amount
})
.then((response) => response.json())
.then((order) => order.id);
},
// Finalize the transaction after payer approval
onApprove: function (data, actions) {
return fetch(`/api/orders/${data.orderID}/capture`, {
method: "post",
})
.then((response) => response.json())
.then((orderData) => {
// Successful capture! For dev/demo purposes:
console.log(
"Capture result",
orderData,
JSON.stringify(orderData, null, 2)
);
const transaction = orderData.purchase_units[0].payments.captures[0];
alert(`Transaction ${transaction.status}: ${transaction.id}
See console for all available details
`);
// When ready to go live, remove the alert and show a success message within this page. For example:
// var element = document.getElementById('paypal-button-container');
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
});
},
})
.render("#paypal-button-container");
// If this returns false or the card fields aren't visible, see Step #1.
if (paypal.HostedFields.isEligible()) {
let orderId;
// Renders card fields
paypal.HostedFields.render({
// Call your server to set up the transaction
createOrder: () => {
return fetch("/api/orders", {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
save: document.querySelector('#save').checked,
card_name: document.getElementById("card-holder-name").value,
billing_address: {
address_line_1: document.getElementById("card-billing-address-street").value,
address_line_2: document.getElementById("card-billing-address-unit").value,
admin_area_2: document.getElementById("card-billing-address-city").value,
admin_area_1: document.getElementById("card-billing-address-state").value,
postal_code: document.getElementById("card-billing-address-zip").value,
country_code: document.getElementById("card-billing-address-country").value
}
})
// use the "body" param to optionally pass additional order information like
// product ids or amount.
})
.then((res) => res.json())
.then((orderData) => {
console.log("==============>create order response<==============");
console.log(orderData);
orderId = orderData.id; // needed later to complete capture
return orderData.id;
});
},
styles: {
".valid": {
color: "green",
},
".invalid": {
color: "red",
},
},
fields: {
number: {
selector: "#card-number",
placeholder: "4111 1111 1111 1111",
},
cvv: {
selector: "#cvv",
placeholder: "123",
},
expirationDate: {
selector: "#expiration-date",
placeholder: "MM/YY",
},
},
}).then((cardFields) => {
document.querySelector("#card-form").addEventListener("submit", (event) => {
event.preventDefault();
cardFields
.submit({
save: document.querySelector('#save').checked,
// Cardholder's first and last name
cardholderName: document.getElementById("card-holder-name").value,
// Billing Address
billingAddress: {
// Street address, line 1
streetAddress: document.getElementById(
"card-billing-address-street"
).value,
// Street address, line 2 (Ex: Unit, Apartment, etc.)
extendedAddress: document.getElementById(
"card-billing-address-unit"
).value,
// State
region: document.getElementById("card-billing-address-state").value,
// City
locality: document.getElementById("card-billing-address-city")
.value,
// Postal Code
postalCode: document.getElementById("card-billing-address-zip")
.value,
// Country Code
countryCodeAlpha2: document.getElementById(
"card-billing-address-country"
).value,
},
})
.then(() => {
fetch(`/api/orders/${orderId}/capture`, {
method: "post",
})
.then((res) => res.json())
.then((orderData) => {
console.log("==============>capture order response<==============");
console.log(orderData);
// Two cases to handle:
// (1) Other non-recoverable errors -> Show a failure message
// (2) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
const errorDetail =
Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail) {
var msg = "Sorry, your transaction could not be processed.";
if (errorDetail.description)
msg += "\n\n" + errorDetail.description;
if (orderData.debug_id) msg += " (" + orderData.debug_id + ")";
return alert(msg); // Show a failure message
}
// Show a success message or redirect
alert("Transaction completed!");
});
})
.catch((err) => {
alert("Payment could not be captured! " + JSON.stringify(err));
});
});
});
} else {
// Hides card fields if the merchant isn't eligible
document.querySelector("#card-form").style = "display: none";
}
paypal-api.js
import fetch from "node-fetch";
// set some important variables
const { CLIENT_ID, APP_SECRET } = process.env;
const base = "https://api-m.sandbox.paypal.com";
// call the create order method
export async function createOrder(body) {
const purchaseAmount = "100.00"; // TODO: pull prices from a database
const accessToken = await generateAccessToken();
const url = `${base}/v2/checkout/orders`;
const response = await fetch(url, {
method: "post",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: body ? JSON.stringify({
intent: "CAPTURE",
purchase_units: [
{
amount: {
currency_code: "USD",
value: purchaseAmount,
},
},
],
payment_source: {
card: {
name: body.card_name,
billing_address: body.billing_address,
attributes: {
vault: {
store_in_vault: 'ON_SUCCESS'
}
}
}
}
}) : undefined,
});
return handleResponse(response);
}
// capture payment for an order
export async function capturePayment(orderId) {
const accessToken = await generateAccessToken();
const url = `${base}/v2/checkout/orders/${orderId}/capture`;
const response = await fetch(url, {
method: "post",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
});
return handleResponse(response);
}
// generate access token
export async function generateAccessToken() {
const auth = Buffer.from(CLIENT_ID + ":" + APP_SECRET).toString("base64");
const response = await fetch(`${base}/v1/oauth2/token`, {
method: "post",
body: "grant_type=client_credentials",
headers: {
Authorization: `Basic ${auth}`,
},
});
const jsonData = await handleResponse(response);
return jsonData.access_token;
}
// generate client token
export async function generateClientToken() {
const accessToken = await generateAccessToken();
const response = await fetch(`${base}/v1/identity/generate-token`, {
method: "post",
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Language": "en_US",
"Content-Type": "application/json",
},
body: JSON.stringify({
customer_id: 'kxIaZbNwOZ'
})
});
const jsonData = await handleResponse(response);
return jsonData.client_token;
}
async function handleResponse(response) {
if (response.status === 200 || response.status === 201) {
return response.json();
}
const errorMessage = await response.text();
throw new Error(errorMessage);
}
server.js
import "dotenv/config";
import express from "express";
import * as paypal from "./paypal-api.js";
const app = express();
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(express.json());
// render checkout page with client id & unique client token
app.get("/", async (req, res) => {
const clientId = process.env.CLIENT_ID;
try {
const clientToken = await paypal.generateClientToken();
res.render("checkout", { clientId, clientToken });
} catch (err) {
res.status(500).send(err.message);
}
});
// create order
app.post("/api/orders", async (req, res) => {
try {
const order = await paypal.createOrder(req.body);
res.json(order);
} catch (err) {
res.status(500).send(err.message);
}
});
// capture payment
app.post("/api/orders/:orderID/capture", async (req, res) => {
const { orderID } = req.params;
try {
const captureData = await paypal.capturePayment(orderID);
res.json(captureData);
} catch (err) {
res.status(500).send(err.message);
}
});
app.listen(8888, () => console.log("App Started."));
Error:
{
"err": "Error: Shipping address requested for card payment\n...",
"timestamp": "1673098647388",
"referer": "www.sandbox.paypal.com",
"sdkCorrelationID": "04103b485b692",
"sessionID": "uid_82aff76087_mtm6mzu6mzk",
"clientID": "AUUbkZiQ1akU7ChP0UxbWN9U8-wR0pYmOUF8gzkXtsrcbn9GXDLB0fjOT14vG-rvWYwGmM7Lzj8LDK-C",
"env": "sandbox",
"buttonSessionID": "uid_05c2d7e1ec_mtm6mzc6mtq",
"buttonCorrelationID": "a17486c9208f5",
"time": "1673098647388",
"user_id": "uid_05c2d7e1ec_mtm6mzc6mtq",
"token": "2VY75292WT2863902"
}
Uncaught Error: Shipping address requested for card payment
at https://www.sandbox.paypal.com/smart/buttons?sdkVersion=5.0.344&style.layout=vertical&style.color=gold&style.shape=rect&style.tagline=false&style.menuPlacement=below&components.0=buttons&components.1=hosted-fields&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jb21wb25lbnRzPWJ1dHRvbnMsaG9zdGVkLWZpZWxkcyZjbGllbnQtaWQ9QVVVYmtaaVExYWtVN0NoUDBVeGJXTjlVOC13UjBwWW1PVUY4Z3prWHRzcmNibjlHWERMQjBmak9UMTR2Ry1ydldZd0dtTTdMemo4TERLLUMiLCJhdHRycyI6eyJkYXRhLXVpZCI6InVpZF9laWVpbXFteW9tY3F4am1xeWd4dGxsZWlld2FvcmIifX0&clientID=AUUbkZiQ1akU7ChP0UxbWN9U8-wR0pYmOUF8gzkXtsrcbn9GXDLB0fjOT14vG-rvWYwGmM7Lzj8LDK-C&clientAccessToken=A21AALuiYv6v0yKLvGRKk4KoMModxjNd_Ph185k19xRLIjbptX_pGsMmYPvM9pTdyuKBwJbDm33J9zeRmkwl9_FbdGY1WtwIw&sdkCorrelationID=04103b485b692&storageID=uid_e93c1270fe_mtm6mzu6mzk&sessionID=uid_82aff76087_mtm6mzu6mzk&buttonSessionID=uid_05c2d7e1ec_mtm6mzc6mtq&env=sandbox&buttonSize=huge&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjp0cnVlLCJwcm9kdWN0cyI6eyJwYXlJbjMiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXJpYW50IjpudWxsfSwicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXJpYW50IjpudWxsfX19LCJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJicmFuZGVkIjpmYWxzZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6dHJ1ZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX0sImd1ZXN0RW5hYmxlZCI6ZmFsc2V9LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJhcHBsZXBheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJzZXBhIjp7ImVsaWdpYmxlIjpmYWxzZX0sImlkZWFsIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJhbmNvbnRhY3QiOnsiZWxpZ2libGUiOmZhbHNlfSwiZ2lyb3BheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlcHMiOnsiZWxpZ2libGUiOmZhbHNlfSwic29mb3J0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm15YmFuayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwMjQiOnsiZWxpZ2libGUiOmZhbHNlfSwiemltcGxlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ3ZWNoYXRwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwicGF5dSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJibGlrIjp7ImVsaWdpYmxlIjpmYWxzZX0sInRydXN0bHkiOnsiZWxpZ2libGUiOmZhbHNlfSwib3h4byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtYXhpbWEiOnsiZWxpZ2libGUiOmZhbHNlfSwiYm9sZXRvIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJvbGV0b2JhbmNhcmlvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm1lcmNhZG9wYWdvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm11bHRpYmFuY28iOnsiZWxpZ2libGUiOmZhbHNlfSwic2F0aXNwYXkiOnsiZWxpZ2libGUiOmZhbHNlfX0&platform=desktop&experiment.enableVenmo=false&experiment.enableVenmoAppLabel=false&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=paylater&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false&experience=&allowBillingPayments=true:1492:261589
at n.dispatch (https://www.sandbox.paypal.com/smart/buttons?sdkVersion=5.0.344&style.layout=vertical&style.color=gold&style.shape=rect&style.tagline=false&style.menuPlacement=below&components.0=buttons&components.1=hosted-fields&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jb21wb25lbnRzPWJ1dHRvbnMsaG9zdGVkLWZpZWxkcyZjbGllbnQtaWQ9QVVVYmtaaVExYWtVN0NoUDBVeGJXTjlVOC13UjBwWW1PVUY4Z3prWHRzcmNibjlHWERMQjBmak9UMTR2Ry1ydldZd0dtTTdMemo4TERLLUMiLCJhdHRycyI6eyJkYXRhLXVpZCI6InVpZF9laWVpbXFteW9tY3F4am1xeWd4dGxsZWlld2FvcmIifX0&clientID=AUUbkZiQ1akU7ChP0UxbWN9U8-wR0pYmOUF8gzkXtsrcbn9GXDLB0fjOT14vG-rvWYwGmM7Lzj8LDK-C&clientAccessToken=A21AALuiYv6v0yKLvGRKk4KoMModxjNd_Ph185k19xRLIjbptX_pGsMmYPvM9pTdyuKBwJbDm33J9zeRmkwl9_FbdGY1WtwIw&sdkCorrelationID=04103b485b692&storageID=uid_e93c1270fe_mtm6mzu6mzk&sessionID=uid_82aff76087_mtm6mzu6mzk&buttonSessionID=uid_05c2d7e1ec_mtm6mzc6mtq&env=sandbox&buttonSize=huge&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjp0cnVlLCJwcm9kdWN0cyI6eyJwYXlJbjMiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXJpYW50IjpudWxsfSwicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXJpYW50IjpudWxsfX19LCJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJicmFuZGVkIjpmYWxzZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6dHJ1ZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX0sImd1ZXN0RW5hYmxlZCI6ZmFsc2V9LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJhcHBsZXBhe
Expecting the payment success

Unexpected token " in JSON at position 0

My Goal for this one is to Add ObjectId inside the array
In my backend Im declare schema on this code:
tchStudents: [{
type: Schema.Types.ObjectId,
ref: "Student"
}]
THen Im do adding an ObjectId to insert to the array of ObjectID:
My BackEnd is very fine
router.put('/assignAddStudents/:tchID', async (req,res) => {
try {
const searchTch = await Teacher.findOne({ tchID: req.params.tchID })
if(!searchTch){
return res.status(404).send({
success: false,
error: 'Teacher ID not found'
});
} else {
let query = { tchID: req.params.tchID }
let assignedStudentObjID = {$push:{tchStudents: req.body.tchStudents }}
Teacher.updateOne(query, assignedStudentObjID ,() => {
try{
return res.status(200).send({
success: true,
msg: 'Student ID has been assigned'
});
} catch(err) {
console.log(err);
return res.status(404).send({
success: false,
error: 'Teacher ID not found'
})
}
})
}
} catch (err) {
console.log(err)
}
})
But my Front End Not working
err: BAD REQUEST(400) Unexpected token " in JSON at position 0
import React, {useState} from 'react'
import axios from 'axios'
import { URL } from '../../utils/utils'
import { Modal, Button } from 'react-materialize';
import ListTchStudents from '../lists/ListTchStudents';
const trigger =
<Button
style={{marginLeft:'2rem'}}
tooltip="Add More..."
tooltipOptions={{
position: 'top'
}}
className="btn-small red darken-4">
<i className="material-icons center ">add_box</i>
</Button>;
const MdlAddStudents =({teacher}) => {
const [data, setData] = useState('');
const { tchStudents} = data;
const {
tchID,
} = teacher; // IF WE RENDER THIS IT TURNS INTO OBJECT
const assignedStudent = () => {
// BUT WE SENT IT TO THE DATABASE CONVERT TO JSON.STRINGIFY to make ObjectId
const requestOpt = {
method: 'PUT',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify(data)
}
axios.put(`${URL}teachers/assignAddStudents/${tchID}`, data,requestOpt)
.then(res => {
setData(res.data.data)
})
}
return (
<Modal header="Add Students" trigger={trigger}>
Please ADD and REMOVE Student ID No. for {tchID}
<div>
<ul
style={{marginBottom:'2rem'}}
className="collection">
{
Object.values(teacher.tchStudents).map(tchStudent => {
return(
<ListTchStudents
tchStudent={tchStudent}
/>
);
})
}
</ul>
<div className="row">
<div className="col s6 offset-s3"></div>
<div className="input-field">
<label
htmlFor=""
className="active black-text"
style={{fontSize:'1.3rem'}}>
Add Students here:
</label>
<input
type="text"
name="tchStudents"
value={(tchStudents)}
className="validate"
onChange={(e) => setData(e.target.value)}
/>
</div>
</div>
</div>
{/* BUT WE SENT IT TO THE DATABASE CONVERT TO JSON.STRINGIFY to send ObjectId to the database
*/}
<div className="row">
<div className="col s2 offset-s3" ></div>
<Button
onClick={assignedStudent}
tooltip="Add Students"
tooltipOptions={{
position: 'right'
}}
className="btn green darken-3">
<i className="material-icons ">add_circle</i>
</Button>
</div>
<p>There are {Object.values(teacher.tchStudents).length} student/s
assigned</p>
</Modal>
)
}
// MdlAddStudents.propTypes = {
// assignedStudents: PropTypes.func.isRequired,
// }
export default MdlAddStudents;
// export default connect(null, (assignedStudents))(MdlAddStudents);
Thank you for helping out
The problem stems from you attempting to wrap your tchStudents state property in an object named data.
My advice is to keep it very simple
// it's just a string
const [tchStudents, setTchStudents] = useState("")
const assignedStudent = () => {
// create your request payload
const data = { tchStudents }
// no config object required
axios.put(`${URL}teachers/assignAddStudents/${tchID}`, data)
.then(res => {
// not sure what you want to do here exactly but
// `res.data` should look like
// { success: true, msg: 'Student ID has been assigned' }
setTchStudents("") // clear the input ¯\_(ツ)_/¯
})
}
The only other change is to use the new setter name in your <input>...
<input
type="text"
name="tchStudents"
value={tchStudents}
className="validate"
onChange={(e) => setTchStudents(e.target.value)}
/>

How do I use data from POST request for the next GET request

I'm trying to build a web app that uses Spotify API now. I want it to send a search keyword that an user submits to the server and send back its search result to the front end. The problem is I get a 404 status code for the fetch call. The POST request works fine.
Main.js
import React, { Component } from "react";
import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
axios
.post(
"http://localhost:4000/search_result",
{
keyword: this.state.keyword,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
}
componentDidMount() {
fetch("http://localhost:4000/api")
.then((res) => res.json)
.then((artists) => {
this.setState({ artists });
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map((elem) => (
<SingerCard
images={elem.images}
name={elem.name}
artists={this.state.artists}
/>
))}
{console.log(this.state.artists)}
</div>
<br />
</div>
);
}
}
export default Main;
server.js
const express = require("express");
const SpotifyWebApi = require("spotify-web-api-node");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const port = 4000 || process.env.PORT;
require("dotenv").config();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
function (data) {
console.log("The access token expires in " + data.body["expires_in"]);
console.log("The access token is " + data.body["access_token"]);
// Save the access token so that it's used in future calls
spotifyApi.setAccessToken(data.body["access_token"]);
},
function (err) {
console.log("Something went wrong when retrieving an access token", err);
}
);
app.post("/search_result", (req, res) => {
console.log(req.body.keyword);
spotifyApi.searchArtists(req.body.keyword).then(function (data) {
var search_res = data.body.artists.items;
res.json(search_res);
app.get("http://localhost:/api", (req, res) => {
res.json(search_res);
res.end();
});
res.end();
}),
function (err) {
console.log(err);
};
});
app.listen(port, () => console.log(`It's running on port ${port}`));
I think the app.get() in the app.post() causes the error but I can't figure out another way to send the search result back.
You're getting a 404 because the get method is not correctly defined.
Update your server code to define the get method to just keep the pathname, like this:
app.get("/api", (req, res) => {
// ...
}
Currently, you are defining this route inside the app.post. The get route definition should be outside of the post route.
Use Axios.get
import React, { Component } from "react";
// import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
};
axios.post(
"https://jsonplaceholder.typicode.com/users",
{ keyword: this.state.keyword },
{ headers: headers }
)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
this.setState({
artists: res.data
});
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map(elem => (
<div key={elem.id}>
<ul>
<li>{elem.name}</li>
</ul>
</div>
))}
</div>
</div>
);
}
}
export default Main;

What is a right way to work with reducer in Redux?

I am building an app, sort of dictionary app. In my app a user can add, update and delete a word. Something happened and now my update function does not work. I don't understand why. When I click an update button an error appears in the console. Your hints and suggestions are appreciated.
Word update API
// #route Put api/words/:id
// #desc Update a word by id
// #access Private
router.put(
'/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateWordInput(req.body);
// Check validation
if (!isValid) {
// Return any errors
return res.status(400).json(errors);
}
Profile.findOne({ user: req.user.id }).then(profile => {
Word.findById(req.params.id).then(word => {
// Check for word owner
if (word.user.toString() !== req.user.id) {
return res.status(401).json({ notauthorized: 'User not authorized' });
}
const wordID = req.params.id;
const wordInput = req.body;
// Update
Word.findByIdAndUpdate(
{ _id: wordID },
{ $set: wordInput },
{ returnOriginal: false },
(err, word) => {
if (err) {
console.log(err);
}
}
)
.then(word => {
res.json(word);
})
.catch(err =>
res
.status(404)
.json({ wordcannotbeupdated: 'word cannot be updated' })
);
});
});
}
);
Word actions
export const updateWord = (id, updatedWord, history) => dispatch => {
axios
.put(`/api/words/${id}`, updatedWord)
.then(res => {
dispatch({
type: UPDATE_WORD,
payload: res.data
});
history.push('/my-words');
})
.catch(err =>
dispatch({
type: UPDATE_WORD,
payload: ''
})
);
};
Word reducer
import {
GET_WORDS_BY_USER,
ADD_WORD,
UPDATE_WORD,
GET_WORD_BY_ID,
DELETE_WORD,
SEARCH_WORD
} from '../actions/types';
const initialState = {
words: [],
word: {},
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case ADD_WORD:
return {
...state,
words: [action.payload, ...state.words]
};
case GET_WORDS_BY_USER:
return {
...state,
words: action.payload
};
case GET_WORD_BY_ID:
return {
...state,
word: action.payload
};
case UPDATE_WORD:
return {
...state,
words: action.payload
};
case SEARCH_WORD:
return {
...state,
words: action.payload
};
case DELETE_WORD:
return {
...state,
words: state.words.filter(word => word._id !== action.payload)
};
default:
return state;
}
}
Edit Word React component
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import TextFieldGroup from '../common/TextFieldGroup';
import SelectListGroup from '../common/SelectListGroup';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { getWordByID, updateWord } from '../../actions/wordActions';
import isEmpty from '../../validation/is-empty';
import {
lexisOptions,
grammarOptions,
partOfSpeechOptions,
styleOptions,
originOptions,
sphereOptions
} from './options';
class EditWord extends Component {
constructor(props) {
super(props);
this.state = {
ugrWordCyr: '',
rusTranslation: '',
example: '',
exampleTranslation: '',
origin: '',
sphere: '',
see: '',
lexis: '',
grammar: '',
partOfSpeech: '',
style: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onCheck = this.onCheck.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
if (nextProps.words.word[0]) {
nextProps.words.word.map(word => {
word.ugrWordCyr = !isEmpty(word.ugrWordCyr) ? word.ugrWordCyr : '';
word.rusTranslation = !isEmpty(word.rusTranslation)
? word.rusTranslation
: '';
word.rusTranslation = !isEmpty(word.rusTranslation)
? word.rusTranslation
: '';
word.example = !isEmpty(word.example) ? word.example : '';
word.exampleTranslation = !isEmpty(word.exampleTranslation)
? word.exampleTranslation
: '';
word.origin = !isEmpty(word.origin) ? word.origin : '';
word.sphere = !isEmpty(word.sphere) ? word.sphere : '';
word.see = !isEmpty(word.see) ? word.see : {};
word.lexis = !isEmpty(word.lexis) ? word.lexis : {};
word.grammar = !isEmpty(word.grammar) ? word.grammar : {};
word.see = !isEmpty(word.see) ? word.see : {};
word.style = !isEmpty(word.style) ? word.style : {};
this.setState({
ugrWordCyr: word.ugrWordCyr,
rusTranslation: word.rusTranslation,
example: word.example,
exampleTranslation: word.exampleTranslation,
origin: word.origin,
sphere: word.sphere,
style: word.style,
lexis: word.lexis,
grammar: word.grammar,
see: word.see,
partOfSpeech: word.partOfSpeech
});
});
}
}
componentDidMount() {
this.props.getWordByID(this.props.match.params.id);
}
onSubmit(e) {
e.preventDefault();
const wordData = {
ugrWordCyr: this.state.ugrWordCyr,
rusTranslation: this.state.rusTranslation,
example: this.state.example,
exampleTranslation: this.state.exampleTranslation,
origin: this.state.origin,
sphere: this.state.sphere,
see: this.state.see,
lexis: this.state.lexis,
grammar: this.state.grammar,
partOfSpeech: this.state.partOfSpeech,
style: this.state.style
};
let id = this.props.match.params.id;
// Change a function to update
this.props.updateWord(id, wordData, this.props.history);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onCheck(e) {
this.setState({
current: !this.state.current
});
}
render() {
const { errors } = this.state;
return (
<div className="add-word">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<Link to="/my-words" className="btn btn-light">
Go Back
</Link>
<h1 className="display-4 text-center">Edit Word</h1>
<form onSubmit={this.onSubmit}>
<TextFieldGroup
placeholder="Бала"
info="Введите слово на уйгурском"
name="ugrWordCyr"
value={this.state.ugrWordCyr}
onChange={this.onChange}
error={errors.ugrWordCyr}
/>
<TextFieldGroup
placeholder="Ребенок"
info="Введите слово на русском"
name="rusTranslation"
value={this.state.rusTranslation}
onChange={this.onChange}
error={errors.rusTranslation}
/>
<div className="form-check mb-form">
<input
type="checkbox"
className="form-check-input"
name="see"
value={this.state.see}
onChange={this.onCheck}
id="see"
/>
<label htmlFor="see">Смотри</label>
</div>
<TextFieldGroup
placeholder=""
info="Введите пример предложения на уйгурском"
name="example"
value={this.state.example}
onChange={this.onChange}
error={errors.example}
/>
<TextFieldGroup
placeholder=""
info="Введите перевод примерного предложения на русском"
name="exampleTranslation"
value={this.state.exampleTranslation}
onChange={this.onChange}
error={errors.exampleTranslation}
/>
<h6>Происхождение слова</h6>
<SelectListGroup
placeholder="Арабское"
name="origin"
value={this.state.origin}
onChange={this.onChange}
error={errors.origin}
options={originOptions}
/>
<h6>Сфера употребления слова</h6>
<SelectListGroup
placeholder="Физика"
name="sphere"
value={this.state.sphere}
onChange={this.onChange}
error={errors.sphere}
options={sphereOptions}
/>
<h6>Лексика слова</h6>
<SelectListGroup
placeholder="лексика"
name="lexis"
value={this.state.lexis}
onChange={this.onChange}
error={errors.lexis}
options={lexisOptions}
/>
<h6>Стиль слова</h6>
<SelectListGroup
placeholder="стиль"
name="style"
value={this.state.style}
onChange={this.onChange}
error={errors.style}
options={styleOptions}
/>
<h6>Часть речи</h6>
<SelectListGroup
placeholder=""
name="partOfSpeech"
value={this.state.partOfSpeech}
onChange={this.onChange}
error={errors.partOfSpeech}
options={partOfSpeechOptions}
/>
<h6>Грамматика слова</h6>
<SelectListGroup
placeholder="грамматика"
name="grammar"
value={this.state.grammar}
onChange={this.onChange}
error={errors.grammar}
options={grammarOptions}
/>
<input
type="submit"
value="submit"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
);
}
}
EditWord.propTypes = {
getWordByID: PropTypes.func.isRequired,
errors: PropTypes.object.isRequired,
updateWord: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
errors: state.errors,
words: state.words
});
export default connect(
mapStateToProps,
{ getWordByID, updateWord }
)(withRouter(EditWord));
axios
.put(/api/words/${id}, updatedWord)
if you are using relative api endpoint then it will be going to request to
<react-server-host:port(which is 3000 in your case)>/api/words/${id}
and i am assuming you are running your backend service on another port than 3000 . Thats why it is giving error 404 not found
So when you are requesting api, write absolute endpoint
<backend-server-host:port>/api/words/${id}

Failed prop type: Invalid prop `errors` of type `string` supplied to `CreateProfile`, expected `object`

I am trying to create a profile for a user on login, after submitting
the form I am getting the error as invalid props errors. As both my
client and server are running.I am using redux in my react app. Below
is my code. I am building a MERN stack application.
I am trying to create a profile for a user on login, after submitting
the form I am getting the error as invalid props errors. As both my
client and server are running.I am using redux in my react app. Below
is my code. I am building a MERN stack application.
import React, { Component } from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import TextFieldGroup from "../common/TextFieldGroup";
import TextAreaFieldGroup from "../common/TextAreaFieldGroup";
import SelectListGroup from "../common/SelectListGroup";
import InputGroup from "../common/InputGroup";
import { createProfile } from "../../actions/profileActions";
class CreateProfile extends Component {
constructor(props) {
super(props);
this.state = {
displaySocialInputs: false,
handle: "",
company: "",
website: "",
location: "",
status: "",
skills: "",
githubusername: "",
bio: "",
twitter: "",
facebook: "",
linkedin: "",
youtube: "",
instagram: "",
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
onSubmit(e) {
e.preventDefault();
const profileData = {
handle: this.state.handle,
company: this.state.company,
website: this.state.website,
location: this.state.location,
status: this.state.status,
skills: this.state.skills,
githubusername: this.state.githubusername,
bio: this.state.bio,
twitter: this.state.twitter,
facebook: this.state.facebook,
linkedin: this.state.linkedin,
youtube: this.state.youtube,
instagram: this.state.instagram
};
this.props.createProfile(profileData, this.props.history);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
const { errors, displaySocialInputs } = this.state;
let socialInputs;
if (displaySocialInputs) {
socialInputs = (
<div>
<InputGroup
placeholder="Twitter Profile URL"
name="twitter"
icon="fab fa-twitter"
value={this.state.twitter}
onChange={this.onChange}
error={errors.twitter}
/>
<InputGroup
placeholder="Facebook Page URL"
name="facebook"
icon="fab fa-facebook"
value={this.state.facebook}
onChange={this.onChange}
error={errors.facebook}
/>
<InputGroup
placeholder="Linkedin Profile URL"
name="linkedin"
icon="fab fa-linkedin"
value={this.state.linkedin}
onChange={this.onChange}
error={errors.linkedin}
/>
<InputGroup
placeholder="YouTube Channel URL"
name="youtube"
icon="fab fa-youtube"
value={this.state.youtube}
onChange={this.onChange}
error={errors.youtube}
/>
<InputGroup
placeholder="Instagram Page URL"
name="instagram"
icon="fab fa-instagram"
value={this.state.instagram}
onChange={this.onChange}
error={errors.instagram}
/>
</div>
);
}
//select options for status
const options = [
{ label: "* Select Professional Status", value: 0 },
{ label: "Developer", value: "Developer" },
{ label: "Junior Developer", value: "Junior Developer" },
{ label: "Senior Developer", value: "Senior Developer" },
{ label: "Manager", value: "Manager" },
{ label: "Student or Learning", value: "Student or Learning" },
{ label: "Instructor or Teacher", value: "Instructor or Teacher" },
{ label: "Intern", value: "Intern" },
{ label: "Other", value: "Other" }
];
return (
<div className="create-profile">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Create Your Profile</h1>
<p className="lead text-center">
Let's get some information to make your profile stand out
</p>
<small className="d-block pb-3">* = required fields</small>
<form onSubmit={this.onSubmit}>
<TextFieldGroup
placeholder="* Profile Handle"
name="handle"
value={this.state.handle}
onChange={this.onChange}
error={errors.handle}
info="A unique handle for your profile URL. Your full name, company name, nickname"
/>
<SelectListGroup
placeholder="Status"
name="status"
value={this.state.status}
onChange={this.onChange}
options={options}
error={errors.status}
info="Give us an idea of where you are at in your career"
/>
<TextFieldGroup
placeholder="Company"
name="company"
value={this.state.company}
onChange={this.onChange}
error={errors.company}
info="Could be your own company or one you work for"
/>
<TextFieldGroup
placeholder="Website"
name="website"
value={this.state.website}
onChange={this.onChange}
error={errors.website}
info="Could be your own website or a company one"
/>
<TextFieldGroup
placeholder="Location"
name="location"
value={this.state.location}
onChange={this.onChange}
error={errors.location}
info="City or city & state suggested (eg. Boston, MA)"
/>
<TextFieldGroup
placeholder="* Skills"
name="skills"
value={this.state.skills}
onChange={this.onChange}
error={errors.skills}
info="Please use comma separated values (eg.
HTML,CSS,JavaScript,PHP"
/>
<TextFieldGroup
placeholder="Github Username"
name="githubusername"
value={this.state.githubusername}
onChange={this.onChange}
error={errors.githubusername}
info="If you want your latest repos and a Github link, include your username"
/>
<TextAreaFieldGroup
placeholder="Short Bio"
name="bio"
value={this.state.bio}
onChange={this.onChange}
error={errors.bio}
info="Tell us a little about yourself"
/>
<div className="mb-3">
<button
type="button"
onClick={() => {
this.setState(prevState => ({
displaySocialInputs: !prevState.displaySocialInputs
}));
}}
className="btn btn-light"
>
Add Social Network Links
</button>
<span className="text-muted">Optional</span>
</div>
{socialInputs}
<input
type="submit"
value="Submit"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
);
}
}
CreateProfile.propTypes = {
profile: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile,
errors: state.errors
});
export default connect(
mapStateToProps,
{ createProfile }
)(withRouter(CreateProfile));
export const createProfile = (profileData, history) => dispatch => {
axios
.post("http://localhost:8080/api/profile", profileData)
.then(res => history.push("/"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
------------------------------------------------------------------
server side route :-
//post - api/profile **private
//create or edit user profile
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
const { errors, isValid } = validateProfileInput(req.body);
// Check Validation
if (!isValid) {
// Return any errors with 400 status
return res.status(400).json(errors);
}
// Get fields
const profileFields = {};
profileFields.user = req.user.id;
if (req.body.handle) profileFields.handle = req.body.handle;
if (req.body.company) profileFields.company = req.body.company;
if (req.body.website) profileFields.website = req.body.website;
if (req.body.location) profileFields.location = req.body.location;
if (req.body.bio) profileFields.bio = req.body.bio;
if (req.body.status) profileFields.status = req.body.status;
if (req.body.githubusername)
profileFields.githubusername = req.body.githubusername;
// Skills - Spilt into array
if (typeof req.body.skills !== "undefined") {
profileFields.skills = req.body.skills.split(",");
}
// Social
profileFields.social = {};
if (req.body.youtube) profileFields.social.youtube = req.body.youtube;
if (req.body.twitter) profileFields.social.twitter = req.body.twitter;
if (req.body.facebook) profileFields.social.facebook = req.body.facebook;
if (req.body.linkedin) profileFields.social.linkedin = req.body.linkedin;
if (req.body.instagram) profileFields.social.instagram = req.body.instagram;
Profile.findOne({ user: req.user.id }).then(profile => {
if (profile) {
// Update
Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
).then(profile => res.json(profile));
} else {
// Create
// Check if handle exists
Profile.findOne({ handle: profileFields.handle }).then(profile => {
if (profile) {
errors.handle = "That handle already exists";
res.status(400).json(errors);
}
// Save Profile
new Profile(profileFields).save().then(profile => res.json(profile));
});
}
});
}
);
Did you check your post route? I had the same issue and solved it writing my route correctly
Try
router.post(
"/api/profile"
instead of
router.post(
"/"
Not sure about it, but I had a typo in my route what solved the exact same issue
There is a problem of authorization you just need to add the jwt token your post request
const token=localStorage.getItem('jwtToken')
var newtoken = token.replace("Bearer","");
export const createprofile = (profileData) =>dispatch =>{
axios
.post('/api/profiles',profileData,{headers:{'Authorization':`Bearer ${newtoken}`}})
.then(res => console.log('Work successfully'))
.catch(err =>
dispatch({
type:GET_ERRORS,
payload:err.response.data
}))
}

Resources