Stripe coupon validation - javascript

I want the user to be able to add a coupon if they have one and by pressing a button the code should check if the coupon exists in my Stripe dashboard. so far I have done this(see code below), I think I'm not missing much but I can't figure out a way to send the validCoupon across from client side to server side and them being able to apply the discount there.
Cart.js (client side)
import React, {useRef, useState} from 'react';
import Link from 'next/link';
import {AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping} from 'react-icons/ai';
import {TiDeleteOutline} from 'react-icons/ti';
import toast from 'react-hot-toast';
import {useStateContext} from '../context/StateContext';
import {urlFor} from '../lib/client';
import getStripe from '../lib/getStripe';
const Cart = () => {
const cartRef = useRef();
const {
totalPrice,
totalQuantities,
cartItems,
setShowCart,
toggleCartItemQuanitity,
onRemove
} = useStateContext();
const [coupontext, setCouponText] = useState('');
const [isCouponAdded, setisCouponAdded] = useState(false);
const [validCoupon, setValidCoupon] = useState("");
const handleChange = (event) => {
setCouponText(event.target.value);
};
const checkCoupon = async () => {
if(!isCouponAdded){
const response = await fetch('https://api.stripe.com/v1/coupons', {
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY}`
}
});
if (!response.ok) {
toast.error("Error fetching coupons");
return;
}
const {data} = await response.json();
const validcoupon = data.find((c) => c.id === coupontext);
if (validcoupon) {
toast.success("Coupon is valid!");
setValidCoupon(validcoupon);
setisCouponAdded(true);
} else {
toast.error("Coupon is invalid!");
}
}else{
toast.success("Coupon already added!");
}
}
const handleCheckout = async () => {
const stripeClient = await getStripe();
const response = await fetch('/api/stripe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartItems)
});
if (response.statusCode === 500)
return;
const data = await response.json();
toast.loading('Redirecting...');
stripeClient.redirectToCheckout({sessionId: data.id});
}
.....
pages/api/stripe.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY);
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
const params = {
submit_type: 'pay',
mode: 'payment',
payment_method_types: ['card'],
billing_address_collection: 'auto',
shipping_address_collection: {
allowed_countries: ["PT"],
},
shipping_options: [
{ shipping_rate: 'shr_1MMq2YJFNgzNJo7sbwDNnqhz' },
{ shipping_rate: "shr_1MMq3iJFNgzNJo7s2nVvfATq"}
],
line_items: req.body.map((item) => {
const img = item.image[0].asset._ref;
const newImage = img.replace('image-', 'https://cdn.sanity.io/images/REDACTED/production/').replace('-png', '.png');
return {
price_data: {
currency: 'eur',
product_data: {
name: item.name,
images: [newImage],
},
unit_amount: item.price * 100,
},
adjustable_quantity: {
enabled:true,
minimum: 1,
},
quantity: item.quantity
}
}),
success_url: `${req.headers.origin}/success`,
cancel_url: `${req.headers.origin}/`,
}
// Create Checkout Sessions from body params.
const session = await stripe.checkout.sessions.create(params);
res.status(200).json(session);
} catch (err) {
res.status(err.statusCode || 500).json(err.message);
}
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
}
//////////////////////////////////////// UPDATE /////////////////////////////////////////
Ok so now I'm adding validCoupon object to the cartsItems and passing in the body. on the server side I'm having issues because no discount is being applied ever, I don't know why but i fell that I'm really close to solving this, just missing something simple.
Cart.js
import React, {useRef, useState} from 'react';
import Link from 'next/link';
import {AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping} from 'react-icons/ai';
import {TiDeleteOutline} from 'react-icons/ti';
import toast from 'react-hot-toast';
import {useStateContext} from '../context/StateContext';
import {urlFor} from '../lib/client';
import getStripe from '../lib/getStripe';
const Cart = () => {
const cartRef = useRef();
const {
totalPrice,
totalQuantities,
cartItems,
setShowCart,
toggleCartItemQuanitity,
onRemove
} = useStateContext();
const [coupontext, setCouponText] = useState('');
const [isCouponAdded, setisCouponAdded] = useState(false);
const [validCoupon, setValidCoupon] = useState(null);
const handleChange = (event) => {
setCouponText(event.target.value);
};
const checkCoupon = async () => {
if(!isCouponAdded){
const response = await fetch('https://api.stripe.com/v1/coupons', {
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY}`
}
});
if (!response.ok) {
toast.error("Error fetching coupons");
return;
}
const {data} = await response.json();
console.log(data);
const validcoupon = data.find((c) => c.id === coupontext);
if (validcoupon) {
toast.success("Coupon is valid!");
setValidCoupon(validcoupon);
setisCouponAdded(true);
} else {
toast.error("Coupon is invalid!");
}
}else{
toast.success("Coupon already added!");
}
}
const handleCheckout = async () => {
const stripeClient = await getStripe();
cartItems['validCoupon'] = validCoupon;
console.log(cartItems);
const response = await fetch('/api/stripe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartItems)
});
if (response.statusCode === 500)
return;
const data = await response.json();
toast.loading('Redirecting...');
stripeClient.redirectToCheckout({sessionId: data.id});
}
pages/api/stripe.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY);
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
const discounts = [];
if(req.body.validCoupon && req.body.validCoupon.id) {
discounts.push({coupon: req.body.validCoupon.id});
}
let shipping_options = [];
const line_items = req.body;
let total_amount = 0;
for (const item of line_items) {
total_amount += item.price * item.quantity;
}
if (total_amount >= 40) {
shipping_options = [
{ shipping_rate: 'shr_1MMq3iJFNgzNJo7s2nVvfATq' },
];
} else {
shipping_options = [
{ shipping_rate: "shr_1MMq2YJFNgzNJo7sbwDNnqhz"}
];
}
const params = {
submit_type: 'pay',
mode: 'payment',
discounts: discounts,
payment_method_types: ['card'],
billing_address_collection: 'auto',
shipping_address_collection: {
allowed_countries: ["PT"],
},
shipping_options: shipping_options,
line_items: req.body.map((item) => {
const img = item.image[0].asset._ref;
const newImage = img.replace('image-', 'https://cdn.sanity.io/images/REDACTED/production/').replace('-png', '.png');
return {
price_data: {
currency: 'eur',
product_data: {
name: item.name,
images: [newImage],
},
unit_amount: item.price * 100,
},
quantity: item.quantity
}
}),
success_url: `${req.headers.origin}/success`,
cancel_url: `${req.headers.origin}/`,
}
// Create Checkout Sessions from body params.
const session = await stripe.checkout.sessions.create(params);
res.status(200).json(session);
} catch (err) {
res.status(err.statusCode || 500).json(err.message);
}
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
}

You need to pass coupon to server by adding it to cartItems and you need to pass stripe coupon name in discount array in session params
import React, {useRef, useState} from 'react';
import Link from 'next/link';
import {AiOutlineMinus, AiOutlinePlus, AiOutlineLeft, AiOutlineShopping} from 'react-icons/ai';
import {TiDeleteOutline} from 'react-icons/ti';
import toast from 'react-hot-toast';
import {useStateContext} from '../context/StateContext';
import {urlFor} from '../lib/client';
import getStripe from '../lib/getStripe';
const Cart = () => {
const cartRef = useRef();
const {
totalPrice,
totalQuantities,
cartItems,
setShowCart,
toggleCartItemQuanitity,
onRemove
} = useStateContext();
const [coupontext, setCouponText] = useState('');
const [isCouponAdded, setisCouponAdded] = useState(false);
const [validCoupon, setValidCoupon] = useState("");
const handleChange = (event) => {
setCouponText(event.target.value);
};
const checkCoupon = async () => {
if(!isCouponAdded){
const response = await fetch('https://api.stripe.com/v1/coupons', {
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY}`
}
});
if (!response.ok) {
toast.error("Error fetching coupons");
return;
}
const {data} = await response.json();
const validcoupon = data.find((c) => c.id === coupontext);
if (validcoupon) {
toast.success("Coupon is valid!");
setValidCoupon(validcoupon);
setisCouponAdded(true);
} else {
toast.error("Coupon is invalid!");
}
}else{
toast.success("Coupon already added!");
}
}
const handleCheckout = async () => {
const stripeClient = await getStripe();
cartItems['validCoupon'] = validCoupon;
const response = await fetch('/api/stripe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartItems)
});
if (response.statusCode === 500)
return;
const data = await response.json();
toast.loading('Redirecting...');
stripeClient.redirectToCheckout({sessionId: data.id});
}
.....
const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY);
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
const params = {
submit_type: 'pay',
mode: 'payment',
discounts: [
{
coupon: "Your_coupon_name_asper_stripe"
}
]
payment_method_types: ['card'],
billing_address_collection: 'auto',
shipping_address_collection: {
allowed_countries: ["PT"],
},
shipping_options: [
{ shipping_rate: 'shr_1MMq2YJFNgzNJo7sbwDNnqhz' },
{ shipping_rate: "shr_1MMq3iJFNgzNJo7s2nVvfATq"}
],
line_items: req.body.map((item) => {
const img = item.image[0].asset._ref;
const newImage = img.replace('image-', 'https://cdn.sanity.io/images/REDACTED/production/').replace('-png', '.png');
return {
price_data: {
currency: 'eur',
product_data: {
name: item.name,
images: [newImage],
},
unit_amount: item.price * 100,
},
adjustable_quantity: {
enabled:true,
minimum: 1,
},
quantity: item.quantity
}
}),
success_url: `${req.headers.origin}/success`,
cancel_url: `${req.headers.origin}/`,
}
// Create Checkout Sessions from body params.
const session = await stripe.checkout.sessions.create(params);
res.status(200).json(session);
} catch (err) {
res.status(err.statusCode || 500).json(err.message);
}
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
}

I included the validCoupon inside the body of the POST request.
const handleCheckout = async () => {
const stripeClient = await getStripe();
const response = await fetch('/api/stripe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
cartItems,
validCoupon
})
});
if (response.statusCode === 500)
return;
const data = await response.json();
toast.loading('Redirecting...');
stripeClient.redirectToCheckout({sessionId: data.id});
}
then on the server side I pulled each object out of the body like this.
const {cartItems, validCoupon} = req.body;
and then used each object separately.
validCoupon.id or cartItems.map

Related

Browser push notification is not showing

I tried to append push notification to a Nextjs app. Referring to this tutorial but the push notification is not showing.
https://www.youtube.com/watch?v=HlYFW2zaYQM
Of course I turn on authorization of notification in chrome browser.
_app.tsx
import { AppProps } from "next/app"
import { useEffect } from "react"
const publicVapidKey = 'blablabla...'
const send = async () => {
console.log("registering serviceWorker")
const register = await navigator.serviceWorker.register("/sw.js", {
scope: "/",
})
console.log("serviceWorker is registered")
console.log("registering push")
const subscription = await register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey),
})
console.log("push is registered")
console.log("sending push..")
await fetch("http://localhost:8000/push", {
method: "POST",
body: JSON.stringify(subscription),
headers: {
"content-type": "application/json",
},
})
console.log("have sent push")
}
// change base64 of VapidKey to Uint8Array
const urlBase64ToUint8Array = (base64String: string) => {
let padding = "=".repeat((4 - (base64String.length % 4)) % 4)
let base64 = (base64String + padding).replace(/\-/g, "+").replace(/_/g, "/")
let rawData = window.atob(base64)
let outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}
function MyApp({ Component, pageProps }: AppProps) {
const { globalIsModalOpen } = useStore()
useEffect(() => {
(async () => {
const result = await Notification.requestPermission()
if (result === "granted") {
console.log("auth ok")
}
})()
if ("serviceWorker" in navigator) {
send().catch((err) => console.error(err))
}
}, [])
return (
<div>
This is example
</div>
)
}
export default MyApp
public/sw.js
self.addEventListener("push", (e) => {
const data = e.data.json();
console.log("have got push notification");
self.registration.showNotification(data.title, {
body: "This is example",
icon:
"https://blablabla...",
});
});
index.js (backend file, separated from Nextjs directory)
const fetch = require('node-fetch')
const express = require('express')
const cors = require('cors')
const webpush = require('web-push')
const app = express()
app.use(cors())
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const publicVapidKey = 'blablabla...';
const privateVapidKey = 'blablabla...';
webpush.setVapidDetails('mailto:example#example.com', publicVapidKey, privateVapidKey);
app.post('/push', async (req, res) => {
const subscription = req.body;
res.status(201).json({ 'success': true })
const payload = JSON.stringify({ title: 'push notification test' });
webpush.sendNotification(subscription, payload).catch(err => console.error(err))
})
app.listen(8000, () => {
console.log('server is running on 8000')
})

Call custom React async hook within a component and se it's state again

I have a custom react hook fetching number of comments from an API that looks like this:
export async function useFetchNumberOfComments(articleId) {
const [numberOfComments, setNumbeOfComments] = useState(0);
useEffect(() => {
(async () => {
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
const data = await response.data;
setNumbeOfComments(data);
} catch (err) {
console.log(err);
}
})();
}, []);
return numberOfComments;
}
And I want to use it in a Article component that looks like this:
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
let { id } = useParams();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
const [title, setTitle] = useState("");
const [author, setAuthor] = useState("");
const [content, setContent] = useState("");
const [comments, setComments] = useState([]);
const [commentAuthor, setCommentAuthor] = useState("");
const [commentContent, setCommentContent] = useState("");
const [imageId, setImageId] = useState("");
const [imageUrl, setImageUrl] = useState("");
const [createdAt, setCreatedAt] = useState();
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// Here, fetch the number of comments from my custom hook and update numOf Comments in this component
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numOfComments})</h4>
</>
);
};
export default SingleArticle;
Now, the problem is that I have no idea how to do the mentioned activity within the Article component: Once the form data(for comment) are sent, trigger the useFetchNumberOfComments custom hook and set the numOfComments state inside article component to the newly fetched data.
I think you'd be better served refactoring the useFetchNumberOfComments hook to return a fetch function and some fetch request meta data, i.e. loading and response and error states.
Example:
export function useFetchNumberOfComments() {
const [numberOfComments, setNumbeOfComments] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchArticleCommentCount = useCallback(async (articleId) => {
setLoading(true);
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: JSON.parse(localStorage.getItem("access_token")),
},
});
const data = await response.data;
setNumbeOfComments(data);
setError(null);
return data;
} catch (err) {
console.log(err);
setError(err);
} finally {
setLoading(false);
}
}, []);
return {
fetchArticleCommentCount,
numberOfComments,
loading,
error
};
};
...
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
const { id } = useParams();
const {
fetchArticleCommentCount,
numberOfComments,
} = useFetchNumberOfComments();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
...
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// await returned comment count and update local state
const commentCount = await fetchArticleCommentCount(id);
setNumOfComments(commentCount);
// or use the updated numberOfComments value returned from hook
fetchArticleCommentCount(id);
// both are available, but you only need one or the other here
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numberOfComments})</h4>
</>
);
};
export default SingleArticle;

How to make component reload automatically after state changes?

In a component, I have a function which allows to create gardens and in another component I have a function which allows to recover these gardens which have just been created. But when I go to the screen of this component, I have to reload my application myself to see the gardens that I have just created, this is not done automatically. How can I do so that once the garden creates my GET request retrieves it automatically?
Here is my component that creates the garden:
export default function FormCreateGarden({navigation}) {
const [loading, setLoading] = useState(false);
const [garden, setGarden] = useState(false);
const [gardenName, setGardenName] = useState('');
const [gardenImage, setGardenImage] = useState({uri: '', type: '', name: ''});
const [isVisible, setIsVisible] = useState(false);
const baseUrl = 'http://127.0.0.1/api';
const submitButton = async () => {
if (!gardenName.trim()) {
alert("Veuillez renter un nom de jardin s'il vous plait!");
return;
}
setLoading(true);
try {
const jsonValue = await AsyncStorage.getItem('user');
const parsedUserData = JSON.parse(jsonValue) || {};
setUser(parsedUserData);
const myHeaders = new Headers();
myHeaders.append('Authorization', `Token ${parsedUserData.token}`);
const photo = {
uri: gardenImage.uri,
type: gardenImage.type,
name: gardenImage.name,
};
const formdata = new FormData();
formdata.append('name', gardenName);
formdata.append('user', parsedUserData.user.id);
formdata.append('image', photo);
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow',
};
const response = await fetch(`${baseUrl}/garden/`, requestOptions);
if (response.status === 201) {
let data = await response.json();
alert(`Votre jardin "${gardenName}" a bien été crée`);
setLoading(false);
setGardenName('');
setGardenImage({uri: '', type: '', name: ''});
navigation.navigate('GardenHome');
} else {
throw new Error('Erreur');
}
} catch (e) {
setLoading(false);
console.log(e.message);
console.log(e);
}
};
return (
<View
style={{
backgroundColor: '#32493c',
paddingLeft: 5,
paddingRight: 5,
marginLeft: 20,
}}>
<Button
title="Valider"
color={'white'}
onPress={submitButton}
/>
</View>
);
}
Here is my component that retrieves the created gardens:
export default function GardenHome() {
const [garden, setGarden] = useState([]);
const [plot, setPlot] = useState([]);
const [loading, setLoading] = useState(false);
const navigation = useNavigation();
const gardenData = async () => {
setLoading(true);
const user = await AsyncStorage.getItem('user');
const parsedUserData = JSON.parse(user);
try {
const response = await axios.get(
`http://127.0.0.1/api/garden?user=${parsedUserData.user.id}`,
{
headers: {
Authorization: `Token ${parsedUserData.token}`,
},
},
);
if (response.status === 200) {
setGarden(response.data);
setLoading(false);
}
} catch (e) {
console.log('Erreur ' + e);
setLoading(false);
}
};
useEffect(() => {
gardenData();
}, []);
}

Axios POST with the server responded with a status of 500 (Internal Server Error)

I'm using ReactJS to build a blog app. I can use axios get, put, delete but NOT POST. Every time I post a new blog, it gives me server responded with a status of 500 (Internal Server Error).
I have been struggle with this issue for a week and couldn't figure out the reason. Thank you very much for your help! Let me know if you need additional information.
Here are my codes:
API
import axios from 'axios'
const baseUrl = `/api/blogs`
let token = null
const setToken = newToken => {
token = `bearer ${newToken}`
}
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const create = async newBlog => {
const config = {headers: { Authorization: token }}
const response = await axios.post(baseUrl, newBlog, config)
return response.data
}
const update = async (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject)
const response = await request
return response.data
}
const remove= async (id) => {
const config = {headers: { Authorization: token }}
const request = axios.delete(`${baseUrl}/${id}`, config)
const response = await request
return response.data
}
const exportedObject = { getAll, create, update, setToken, remove }
export default exportedObject
Frontend App.js
import React, { useState, useEffect, useRef } from 'react'
import blogService from './services/blogs'
import loginService from './services/login'
import Blog from './components/Blog'
import LoginForm from './components/LoginForm'
import BlogForm from './components/BlogForm'
import Togglable from './components/Togglable'
import Notification from './components/Notification'
import axios from 'axios'
const App = () => {
const [blogs, setBlogs] = useState([])
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [user, setUser] = useState(null)
const [loginVisible, setLoginVisible] = useState(false)
const [notificationText, setNotificationText] = useState("")
const [notificationStyle, setNotificationStyle] = useState("notification")
const [Toggle, setToggle] = useState(false)
const BlogFormRef = useRef()
useEffect(() => {
const Data = async () => {
const initialBlogs = await blogService.getAll()
setBlogs( initialBlogs )
}
Data()
}, [])
useEffect(() => {
const loggedUserJSON = window.localStorage.getItem('loggedBlogUser')
if (loggedUserJSON) {
const user = JSON.parse(loggedUserJSON)
setUser(user)
blogService.setToken(user.token)
}
}, [])
const addBlog = async (blogObject) => {
BlogFormRef.current.toggleVisibility()
if (blogObject.title !== '' && blogObject.author !== '' && blogObject.url !== '') {
const newBlog = await blogService.create(blogObject)
setBlogs(blogs.concat(newBlog))
setNotificationStyle('notification')
setNotificationText(`A new blog ${blogObject.title} by ${blogObject.author} is added`)
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
setBlogs('')
console.log(blogObject)
document.location.reload()
} else {
setNotificationStyle('Warning')
setNotificationText('You must fill all fields to create a blog')
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
}
}
Backend
const blogsRouter = require('express').Router()
const Blog = require('../models/blog')
const User = require('../models/user')
const jwt = require('jsonwebtoken')
const middleware = require("../utils/middleware")
blogsRouter.get('/', async (request, response) => {
const blogs = await Blog.find({}).populate('user', { username: 1, name: 1 })
response.json(blogs)
})
blogsRouter.get('/:id', (request, response) => {
Blog.findById(request.params.id)
.then(blog => {
if (blog) {
response.json(blog)
} else {
response.status(404).end()
}
})
})
blogsRouter.post('/', middleware.userExtractor, async (request, response) => {
const body = request.body
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if (!decodedToken.id){
return response.status(401).json({error: 'token missing or invalid'})
}
if(body.title === undefined){
return response.status(400).send({
error: 'title is missing'
})
}
else if(body.author === undefined){
return response.status(400).send({
error: 'author is missing'
})
}
else if(body.url === undefined){
return response.status(400).send({
error: 'url is missing'
})
}
else{
const blog = new Blog({
title: body.title,
author: body.author,
url: body.url,
likes: body.likes,
user: user.id
})
const savedBlog = await blog.save()
//console.log(savedBlog)
//console.log(user)
user.blogs = user.blogs.concat(savedBlog.id)
await user.save()
const populatedBlog = await savedBlog.populate('user', { username: 1, name: 1 }).execPopulate()
response.status(200).json(populatedBlog.toJSON())
}
})
blogsRouter.delete('/:id', middleware.userExtractor, async (request, response) => {
const blog = await Blog.findByIdAndRemove(request.params.id)
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if(! request.token || !decodedToken.id){
return response.status(401).json({error:'token is missing or invalid'})
}
else if(blog.user.toString() === user.id.toString()){
await Blog.findByIdAndRemove(request.params.id)
response.status(204).end()
}
else{
return response.status(401).json({error:'cannot process deletion'})
}
})
blogsRouter.put('/:id', async (request, response) => {
const body = request.body
const blog = {
title: body.title,
author:body.author,
url: body.url,
likes: body.likes
}
await Blog.findByIdAndUpdate(request.params.id, blog, { new: true })
.then(updatedBlog => {
response.json(updatedBlog)
})
})
module.exports = blogsRouter
Mongoose
const mongoose = require('mongoose')
const blogSchema = new mongoose.Schema({
title: {type:String,
required: true},
author:{type:String,
required: true},
url: {type:String,
required: true},
likes: {type:Number,
default: 0},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'}
})
blogSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
}
})
const Blog = mongoose.model('Blog', blogSchema)
module.exports = Blog
Additional information: terminate output, the info is actually POST just cannot render in the front
terminal output

React registraion

I`m new in react, and I get problem with registration:
http.hook.js:17 POST http://localhost:3000/api/auth/register 500 (Internal Server Error)
Error: Что-то пошло не так :(, попробуйте снова
at http.hook.js:21
at async registerHandler (Registration.js:24)
code http.hook.js :
import {useState, useCallback} from 'react';
export const useHttp = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const request = useCallback( async (url, method = 'GET', body = null, headers = {}) => {
setLoading(true);
try {
if (body) {
body = JSON.stringify(body);
headers['Content-Type'] = 'application/json'
}
const response = await fetch(url, {method, body, headers});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Что-то пошло не так :(');
};
setLoading(false);
return data;
} catch (e) {
console.log(e)
setLoading(false);
setError(e.message);
throw e;
}
}, [])
const clearError = useCallback( () => setError(null), []);
return { loading, request, error, clearError }
}
and code Registration.js without front-end:
import React, { useState, useEffect } from 'react';
import { useHttp } from '../hooks/http.hook';
import { useMessage } from '../hooks/message.hook';
export const Registration = () => {
const message = useMessage();
const {loading, error, request, clearError} = useHttp();
const [form, setForm] = useState({
nick: '', email: '', password:''
});
useEffect(() => {
console.log(error);
message(error);
clearError();
}, [error, message, clearError]);
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value });
};
const registerHandler = async () => {
try {
const data = await request('/api/auth/register', 'POST', {...form});
console.log('Data', data)
} catch (e) {
console.log(e)
}
};
I think the problem with your server-side.
HTTP response code 500 means that the server encountered an unexpected condition.
Test your endpoint by curl or XHR request.
Also maybe you send not valid data.

Categories