Skip to content

Commit

Permalink
Complete Stripe integration with order creation functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathaniel81 committed May 10, 2024
1 parent d0cb273 commit 3d173ac
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 17 deletions.
2 changes: 1 addition & 1 deletion core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


urlpatterns = [
path('', views.ProductsAPIView.as_view(), name='products'),
path('', views.ProductsAPIView.as_view(), name='products'),
path('search/', views.SearchProductsAPIView.as_view(), name='search_posts'),
path('categories/', views.CategoriesAPIView.as_view(), name='categories'),
path('<str:pk>/save/', views.SaveProductView.as_view(), name='save_product'),
Expand Down
47 changes: 47 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@tanstack/react-query": "^5.32.1",
"axios": "^1.6.8",
"embla-carousel-react": "^8.0.2",
"query-string": "^9.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.3",
Expand Down
84 changes: 75 additions & 9 deletions frontend/src/components/shared/cart/CartPayment.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { SiMediamarkt } from "react-icons/si";
import FormattedPrice from "../../FormattedPrice";
import {
// useDispatch,
useDispatch,
useSelector
} from "react-redux";
import { StateProps, StoreProduct } from "../../../types";
import { useEffect, useState } from "react";
// import { loadStripe } from "@stripe/stripe-js";
import { useNavigate, useLocation } from "react-router-dom";
import axios from 'axios';
import { toast } from "react-toastify";
import QueryString from 'query-string';
import { resetUser, resetCart } from "../../../redux/slices/appSlice";


const CartPayment = () => {
const { productData, userInfo } = useSelector(
(state: StateProps) => state.app
);
const location = useLocation();
const dispatch = useDispatch();

const navigate = useNavigate();
const [totalAmount, setTotalAmount] = useState(0);

useEffect(() => {
let amt = 0;
productData.map((item: StoreProduct) => {
Expand All @@ -23,7 +32,62 @@ const CartPayment = () => {
setTotalAmount(amt);
}, [productData]);

useEffect(() => {
const fetchData = async () => {
try {
const values = QueryString.parse(location.search);

if (values.success) {
const response = await axios.post(
`/api/stripe/confirm_payment/`,
{
session_id: values.session_id,
items: productData
}
);
if (response.data.status === 'Payment was successful and order was created') {
toast.success("Order placed! You will receive an email confirmation.");
dispatch(resetCart());
navigate('/');
} else {
toast.error("Error confirming payment");
}
}

if (values.canceled) {
toast.info("Order canceled -- continue to shop around and checkout when you're ready");
navigate('/');
}
//eslint-disable-next-line
} catch (error: any) {
console.error(error.response.data);
toast.error("Error confirming payment");
}
};

const values = QueryString.parse(location.search);
if (values.success || values.canceled) {
fetchData();
}
//eslint-disable-next-line
}, [location.search]);


const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
try {
const response = await axios.post<{ url: string }>(`/api/stripe/`, {items: productData})

if (response.data.url) {
window.location.href = response.data.url;
}
} catch (error) {
toast.error('Login Required');
dispatch(resetUser());
}
};


return (
<div className="flex flex-col gap-4">
<div className="flex gap-2">
Expand All @@ -42,14 +106,16 @@ const CartPayment = () => {
</span>
</p>
{userInfo ? (
<div className="flex flex-col items-center">
<button
// onClick={handleCheckout}
className="w-full h-10 text-sm font-semibold bg-amazon_blue text-white rounded-lg hover:bg-amazon_yellow hover:text-black duration-300"
>
Proceed to Buy
<form
className="flex flex-col items-center"
onSubmit={handleSubmit}
>
<button
className="w-full h-10 text-sm font-semibold bg-amazon_blue text-white rounded-lg hover:bg-amazon_yellow hover:text-black duration-300"
type='submit'>
Checkout
</button>
</div>
</form>
) : (
<div className="flex flex-col items-center">
<button className="w-full h-10 text-sm font-semibold bg-amazon_blue bg-opacity-50 text-white rounded-lg cursor-not-allowed">
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
export const headerIcons = [
{
imgURL: "/static/assets/images/cartIcon.png",
imgURL: "/assets/images/cartIcon.png",
},
{
imgURL: "/static/assets/images/logo.png",
imgURL: "/assets/images/logo.png",
},
]

export const sliderImages = [
{
imgURL: "/static/assets/images/slider/sliderImg_1.jpg",
imgURL: "/assets/images/slider/sliderImg_1.jpg",
},
{
imgURL: "/static/assets/images/slider/sliderImg_2.jpg",
imgURL: "/assets/images/slider/sliderImg_2.jpg",
},
{
imgURL: "/static/assets/images/slider/sliderImg_3.jpg",
imgURL: "/assets/images/slider/sliderImg_3.jpg",
},
]
4 changes: 2 additions & 2 deletions payment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class StripeCheckoutView(APIView):

def post(self, request):
if request.user.is_anonymous:
raise PermissionDenied("You must be logged in to unsave a product")
raise PermissionDenied("You must be logged in")
line_items = []
for item in request.data.get('items', []):
try:
Expand Down Expand Up @@ -80,7 +80,7 @@ def post(self, request):
paidAt=timezone.now()
)

# Create OrderItems for each item in the cart and decrease product countInStock
# Create OrderItems for each item in the cart and decrease products countInStock
for item in cart_items:
product = Product.objects.get(id=item['id'])
OrderItem.objects.create(
Expand Down
6 changes: 6 additions & 0 deletions shopnest/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@

ALLOWED_HOSTS = ['*']

CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True


# Application definition

Expand Down Expand Up @@ -193,6 +197,8 @@

USE_TZ = True

STRIPE_SECRET_KEY=os.getenv('STRIPE_SECRET_KEY')
SITE_URL = 'http://localhost:5173/#/cart'

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
Expand Down

0 comments on commit 3d173ac

Please sign in to comment.