Skip to content

Commit 26a8fb6

Browse files
committed
fix payment bugs
1 parent f5e341f commit 26a8fb6

File tree

6 files changed

+319
-8
lines changed

6 files changed

+319
-8
lines changed

package-lock.json

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
"@emotion/styled": "^11.11.5",
1515
"@mui/material": "^5.15.19",
1616
"@smastrom/react-rating": "^1.5.0",
17+
"@stripe/react-stripe-js": "^2.7.1",
18+
"@stripe/stripe-js": "^3.5.0",
1719
"@tanstack/react-query": "^5.40.1",
1820
"axios": "^1.7.2",
1921
"date-fns": "^3.6.0",

src/Pages/DashBoard/Add Task/AddTask.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import useAuth from "../../../Hooks/useAuth";
55
import useAxiosSecure from "../../../Hooks/useAxiosSecure";
66
import Swal from "sweetalert2";
77
import useAdmin from "../../../Hooks/useAdmin";
8+
import { useNavigate } from "react-router-dom";
89

910
const image_hosting_key = import.meta.env.VITE_IMAGE_HOSTING_KEY;
1011
const image_hosting_api = `https://api.imgbb.com/1/upload?key=${image_hosting_key}`;
@@ -14,6 +15,7 @@ const AddTask = () => {
1415
const adminCoin = isAdmin?.coins;
1516
const axiosPublic = useAxiosPublic()
1617
const axiosSecure = useAxiosSecure()
18+
const navigate = useNavigate()
1719
const {
1820
register,
1921
handleSubmit,
@@ -71,6 +73,7 @@ const AddTask = () => {
7173
text: "Please Purchase Coin From below link",
7274
footer: '<Link to="">Purchase Coin</Link>'
7375
});
76+
navigate('/dashboard/clientHome')
7477
}
7578

7679

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
2+
import { useEffect, useState } from "react";
3+
import useAxiosSecure from "../../../../Hooks/useAxiosSecure";
4+
import { useQuery } from "@tanstack/react-query";
5+
import SectionTitle from "../../../../Component/SectionTitle";
6+
import { TiDelete } from "react-icons/ti";
7+
import Swal from "sweetalert2";
8+
import useAuth from "../../../../Hooks/useAuth";
9+
10+
11+
const CheckoutForm = () => {
12+
const [error, setError] = useState();
13+
const [clientSecret,setClientSecret] = useState('')
14+
const [transactionId,setTransactionId] = useState('')
15+
const stripe = useStripe();
16+
const elements = useElements();
17+
const axiosSecure = useAxiosSecure();
18+
const {user} = useAuth()
19+
const { data: cart = [], refetch } = useQuery({
20+
queryKey: ["cart"],
21+
queryFn: async () => {
22+
const res = await axiosSecure.get(`/cart/${user?.email}`);
23+
return res.data;
24+
},
25+
});
26+
console.log(cart);
27+
const totalPrice = cart?.reduce((total, item) => total + item.price, 0);
28+
const totalCoins = cart?.reduce((total, item) => total + item.coins, 0);
29+
console.log(totalPrice);
30+
useEffect(() => {
31+
axiosSecure.post('/create-payment-intent',{price:totalPrice})
32+
.then(res =>{
33+
console.log(res.data.clientSecret);
34+
setClientSecret(res.data.clientSecret)
35+
})
36+
},[axiosSecure,totalPrice])
37+
const handleSubmit = async (event) => {
38+
event.preventDefault();
39+
if (!stripe || !elements) {
40+
// Stripe.js has not loaded yet. Make sure to disable
41+
// form submission until Stripe.js has loaded.
42+
return;
43+
}
44+
45+
// Get a reference to a mounted CardElement. Elements knows how
46+
// to find your CardElement because there can only ever be one of
47+
// each type of element.
48+
const card = elements.getElement(CardElement);
49+
50+
if (card == null) {
51+
return;
52+
}
53+
54+
// Use your card Element with other Stripe.js APIs
55+
const { error, paymentMethod } = await stripe.createPaymentMethod({
56+
type: "card",
57+
card,
58+
});
59+
60+
if (error) {
61+
console.log("[error]", error);
62+
setError(error.message);
63+
} else {
64+
console.log("[PaymentMethod]", paymentMethod);
65+
setError("");
66+
}
67+
//confirm payment
68+
const {paymentIntent,error:confirmError} = await stripe.confirmCardPayment(clientSecret,{
69+
payment_method:{
70+
card:card,
71+
billing_details:{
72+
email:user?.email || 'anonymus',
73+
name:user?.displayName || 'anonymus'
74+
}
75+
}
76+
})
77+
if (confirmError) {
78+
console.log("confirm error");
79+
}
80+
else{
81+
console.log("paymentIntent",paymentIntent);
82+
if (paymentIntent.status === 'succeeded') {
83+
console.log('transation id:',paymentIntent.id);
84+
setTransactionId(paymentIntent.id)
85+
const payment = {
86+
transactionId:paymentIntent.id,
87+
email:user?.email,
88+
price:totalPrice,
89+
date:new Date(),
90+
cardId:cart.map(item => item._id),
91+
}
92+
const res = await axiosSecure.post('/payment',payment)
93+
console.log(res.data);
94+
}
95+
}
96+
};
97+
const handleDelete = async (id) => {
98+
console.log(id);
99+
const res = await axiosSecure.delete(`/cart/${id}`);
100+
console.log(res.data);
101+
if (res.data.deletedCount > 0) {
102+
refetch();
103+
Swal.fire({
104+
position: "center",
105+
icon: "success",
106+
title: "Order has been deleted",
107+
showConfirmButton: false,
108+
timer: 1500,
109+
});
110+
}
111+
};
112+
return (
113+
<div>
114+
<div>
115+
<SectionTitle
116+
subHeading={"Buy Now"}
117+
heading={"all order"}
118+
></SectionTitle>
119+
<div className="mt-10 mb-10">
120+
<div className="stats shadow">
121+
122+
<div className="stat">
123+
<div className="stat-title">Total Cost</div>
124+
<div className="stat-value">{totalPrice} $</div>
125+
</div>
126+
127+
</div>
128+
{cart?.length === 0 ? (
129+
<div className="text-center text-2xl">
130+
<h1>No Order</h1>
131+
<p>Please Order Now</p>
132+
</div>
133+
) : (
134+
<div className="overflow-x-auto">
135+
<table className="table table-xs">
136+
<thead>
137+
<tr>
138+
<th>#</th>
139+
<th>Name</th>
140+
<th>Price</th>
141+
<th>Delete</th>
142+
</tr>
143+
</thead>
144+
<tbody>
145+
{cart?.map((item, index) => (
146+
<tr key={item._id}>
147+
<th>{index + 1}</th>
148+
<td>{item.heading}</td>
149+
<td>{item.price}</td>
150+
<td>
151+
{" "}
152+
<TiDelete
153+
onClick={() => handleDelete(item._id)}
154+
className="text-orange-400 text-2xl cursor-pointer"
155+
/>{" "}
156+
</td>
157+
</tr>
158+
))}
159+
</tbody>
160+
</table>
161+
</div>
162+
)}
163+
</div>
164+
</div>
165+
<form onSubmit={handleSubmit}>
166+
<CardElement
167+
options={{
168+
style: {
169+
base: {
170+
fontSize: "16px",
171+
color: "#424770",
172+
"::placeholder": {
173+
color: "#aab7c4",
174+
},
175+
},
176+
invalid: {
177+
color: "#9e2146",
178+
},
179+
},
180+
}}
181+
/>
182+
<button
183+
className="btn btn-primary my-4"
184+
type="submit"
185+
disabled={!stripe }
186+
>
187+
Pay
188+
</button>
189+
<p className="text-red-600">{error}</p>
190+
{
191+
transactionId && <p className="text-green-500">You Transaction id:{transactionId}</p>
192+
}
193+
</form>
194+
</div>
195+
);
196+
};
197+
198+
export default CheckoutForm;

src/Pages/DashBoard/Client/Home/ClientHome.jsx

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,29 @@ import useAxiosSecure from "../../../../Hooks/useAxiosSecure";
55
import { IoCheckmarkCircleSharp } from "react-icons/io5";
66
import { TiDelete } from "react-icons/ti";
77
import Swal from "sweetalert2";
8+
import { FaCoins } from "react-icons/fa";
9+
import { useNavigate } from "react-router-dom";
810

911
const ClientHome = () => {
1012
const [isAdmin] = useAdmin();
1113
const axiosSecure = useAxiosSecure();
14+
const navigate = useNavigate()
15+
1216
const { data: tasks = [], refetch } = useQuery({
1317
queryKey: ["submission"],
1418
queryFn: async () => {
1519
const res = await axiosSecure.get("/submission");
1620
return res.data;
1721
},
1822
});
23+
const { data: coins = [] } = useQuery({
24+
queryKey: ["coins"],
25+
queryFn: async () => {
26+
const res = await axiosSecure.get("/coin");
27+
return res.data;
28+
},
29+
});
30+
1931

2032
const pending = tasks.filter((item) => item.status === "pending");
2133

@@ -88,18 +100,58 @@ const ClientHome = () => {
88100
}
89101
});
90102
};
103+
const handleBuy =async (coin) =>{
104+
const email= isAdmin?.email;
105+
const {coins,price,heading} =coin;
106+
const order = {
107+
heading,
108+
email,
109+
coins,
110+
price
111+
}
112+
const res = await axiosSecure.post('/cart',order)
113+
if(res.data.insertedId){
114+
navigate('/dashboard/buyCoin')
115+
}
116+
}
91117
return (
92118
<div>
93119
<SectionTitle
94120
subHeading={"Client Home"}
95121
heading={"Activity"}
96122
></SectionTitle>
97123
<div className="p-4">
98-
<div className="text-xl font-semibold grid md:grid-cols-3 grid-cols-1">
99-
<h2>Available coin:{isAdmin?.coins}</h2>
100-
<h2>Panding :{pending?.length}</h2>
101-
<h2>Total Pay:{isAdmin?.total_pay}</h2>
102-
</div>
124+
<div className="stats shadow stats-vertical lg:stats-horizontal">
125+
126+
<div className="stat">
127+
<div className="stat-figure text-secondary">
128+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="inline-block w-8 h-8 stroke-current"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
129+
</div>
130+
<div className="stat-title">Available coin</div>
131+
<div className="stat-value">{isAdmin?.coins}</div>
132+
</div>
133+
134+
<div className="stat">
135+
<div className="stat-figure text-secondary">
136+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="inline-block w-8 h-8 stroke-current"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path></svg>
137+
</div>
138+
<div className="stat-title">Panding :</div>
139+
<div className="stat-value">{pending?.length}</div>
140+
141+
</div>
142+
143+
<div className="stat">
144+
<div className="stat-figure text-secondary">
145+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="inline-block w-8 h-8 stroke-current"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"></path></svg>
146+
</div>
147+
<div className="stat-title">Total Pay:</div>
148+
<div className="stat-value">{isAdmin?.total_pay}</div>
149+
150+
151+
</div>
152+
153+
</div>
154+
103155
<div>
104156
<div className="overflow-x-auto">
105157
<table className="table">
@@ -171,6 +223,34 @@ const ClientHome = () => {
171223
</table>
172224
</div>
173225
</div>
226+
{/* */}
227+
<div className=" mt-10">
228+
<div className="text-center">
229+
<h1 className="text-2xl font-bold text-center">Our Packages</h1>
230+
</div>
231+
<div className="mt-10 grid md:grid-cols-3 grid-cols-1 gap-5">
232+
233+
{
234+
coins?.map(coin => <div key={coin._id} className="card card-compact bg-base-100 shadow">
235+
<figure className="m-4">
236+
<FaCoins className="text-6xl text-orange-500" />
237+
</figure>
238+
<div className="card-body">
239+
<h2 className="card-title">{coin.heading}</h2>
240+
<p>Purchase digital coins effortlessly for seamless transactions and investment opportunities.</p>
241+
<div className="card-actions">
242+
<button onClick={() =>handleBuy(coin)} className="btn btn-primary w-full">Buy Now</button>
243+
</div>
244+
</div>
245+
</div>)
246+
}
247+
248+
249+
250+
251+
</div>
252+
</div>
253+
{/* */}
174254
</div>
175255
</div>
176256
);

0 commit comments

Comments
 (0)