From 5ece2baea99fcacbee9a30b70d03ec043c400aa7 Mon Sep 17 00:00:00 2001 From: Victor Turgeon <76506447+Medenos@users.noreply.github.com> Date: Sun, 27 Nov 2022 12:02:00 -0500 Subject: [PATCH] Front-end pour Stripe --- .../grosses-mitaines-ui/package-lock.json | 33 +++ .../grosses-mitaines-ui/package.json | 2 + .../src/components/PaymentForm.js | 105 ++++++++++ .../src/components/StripeContainer.js | 19 ++ .../src/components/TotalProductsPrice.js | 6 - .../src/pages/ReviewInvoice.js | 188 +++++++----------- .../src/stylesheets/site.css | 54 ++++- 7 files changed, 284 insertions(+), 123 deletions(-) create mode 100644 GrossesMitaines/grosses-mitaines-ui/src/components/PaymentForm.js create mode 100644 GrossesMitaines/grosses-mitaines-ui/src/components/StripeContainer.js diff --git a/GrossesMitaines/grosses-mitaines-ui/package-lock.json b/GrossesMitaines/grosses-mitaines-ui/package-lock.json index 8cc8053..83ccff9 100644 --- a/GrossesMitaines/grosses-mitaines-ui/package-lock.json +++ b/GrossesMitaines/grosses-mitaines-ui/package-lock.json @@ -11,6 +11,8 @@ "@fortawesome/fontawesome-svg-core": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/react-fontawesome": "^0.2.0", + "@stripe/react-stripe-js": "^1.15.0", + "@stripe/stripe-js": "^1.44.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -3395,6 +3397,24 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@stripe/react-stripe-js": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.15.0.tgz", + "integrity": "sha512-nqIOuAbbAN1p/zj2d2vykMzd097ZiHbu0+EpPRcfiswBRQIQIZaPrUwmj6HGD8BRA6Wp89mZen1UJbqtsfc3ZA==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@stripe/stripe-js": "^1.44.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@stripe/stripe-js": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.44.1.tgz", + "integrity": "sha512-DKj3U6tS+sCNsSXsoZbOl5gDrAVD3cAZ9QCiVSykLC3iJo085kkmw/3BAACRH54Bq2bN34yySuH6G1SLh2xHXA==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -21007,6 +21027,19 @@ "@sinonjs/commons": "^1.7.0" } }, + "@stripe/react-stripe-js": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.15.0.tgz", + "integrity": "sha512-nqIOuAbbAN1p/zj2d2vykMzd097ZiHbu0+EpPRcfiswBRQIQIZaPrUwmj6HGD8BRA6Wp89mZen1UJbqtsfc3ZA==", + "requires": { + "prop-types": "^15.7.2" + } + }, + "@stripe/stripe-js": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.44.1.tgz", + "integrity": "sha512-DKj3U6tS+sCNsSXsoZbOl5gDrAVD3cAZ9QCiVSykLC3iJo085kkmw/3BAACRH54Bq2bN34yySuH6G1SLh2xHXA==" + }, "@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", diff --git a/GrossesMitaines/grosses-mitaines-ui/package.json b/GrossesMitaines/grosses-mitaines-ui/package.json index 22107dd..484939e 100644 --- a/GrossesMitaines/grosses-mitaines-ui/package.json +++ b/GrossesMitaines/grosses-mitaines-ui/package.json @@ -6,6 +6,8 @@ "@fortawesome/fontawesome-svg-core": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/react-fontawesome": "^0.2.0", + "@stripe/react-stripe-js": "^1.15.0", + "@stripe/stripe-js": "^1.44.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", diff --git a/GrossesMitaines/grosses-mitaines-ui/src/components/PaymentForm.js b/GrossesMitaines/grosses-mitaines-ui/src/components/PaymentForm.js new file mode 100644 index 0000000..072ee4f --- /dev/null +++ b/GrossesMitaines/grosses-mitaines-ui/src/components/PaymentForm.js @@ -0,0 +1,105 @@ +import React, { useState } from "react" +import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js" +import { Button } from "react-bootstrap" + +const CARD_OPTIONS = { + iconStyle: "solid", + style: { + base: { + iconColor: "black", + color: "white", + fontWeight: 500, + fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif", + fontSize: "16px", + fontSmoothing: "antialiased", + ":-webkit-autofill": { color: "beige" }, + "::placeholder": { color: "lightgray" } + }, + invalid: { + iconColor: "red", + color: "red" + } + } +} + + + +const PaymentForm = ({ cost }) => { + + const [success, setSuccess] = useState(false); + const stripe = useStripe(); + const elements = useElements(); + + const handleSubmit = async (e) => { + e.preventDefault(); + const { error, paymentMethod } = await stripe.createPaymentMethod({ + type: "card", + card: elements.getElement(CardElement) + }) + + if (cost <= 0) { + console.log("Coût invalide: ", cost); + return; + } + + if (!error) { + const { id } = paymentMethod; + + const json = JSON.stringify({ amount: cost, stripeId: id }); + + + fetch(`https://localhost:7292/api/Payment`, { + method: 'POST', + credentials: 'include', + mode: 'cors', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: json + }).then((response) => { + if (response.ok) { + console.log("Successful payment"); + setSuccess(true); + } + else { + console.log(response); + } + }).catch((error) => { + console.log("Error: ", error); + }) + + } + else { + console.log(error.message); + } + } + + + + return ( + <> + {!success ? +
+
+
+ +
+
+
+ +
+
+ : +
+

+ L'achat s'est déroulé avec succès +

+
+ } + + ) + +} + +export default PaymentForm; \ No newline at end of file diff --git a/GrossesMitaines/grosses-mitaines-ui/src/components/StripeContainer.js b/GrossesMitaines/grosses-mitaines-ui/src/components/StripeContainer.js new file mode 100644 index 0000000..c5d2b93 --- /dev/null +++ b/GrossesMitaines/grosses-mitaines-ui/src/components/StripeContainer.js @@ -0,0 +1,19 @@ +import React from "react"; +import { loadStripe } from "@stripe/stripe-js" +import { Elements } from "@stripe/react-stripe-js" +import PaymentForm from "./PaymentForm"; + +const PUBLIC_KEY = "pk_test_51M8mzOEerenEZcQIUmJIrmsaZeeNlOil2G1JcMvvO68w50MJr8rDwUjVO44a8dDhSlsRH4GdzH9rDqtkg4Rtbzco00NqkHdn3H"; + +const stripeTestPromise = loadStripe(PUBLIC_KEY); + +const StripeContainer = ({cost}) => { + return ( + + + + ) +} + + +export default StripeContainer; \ No newline at end of file diff --git a/GrossesMitaines/grosses-mitaines-ui/src/components/TotalProductsPrice.js b/GrossesMitaines/grosses-mitaines-ui/src/components/TotalProductsPrice.js index 400de19..75e3052 100644 --- a/GrossesMitaines/grosses-mitaines-ui/src/components/TotalProductsPrice.js +++ b/GrossesMitaines/grosses-mitaines-ui/src/components/TotalProductsPrice.js @@ -5,9 +5,6 @@ export function TotalProductsPrice(/*{ products }*/) { const cart = useContext(CartContext); - // const productTotal = (p) => { - // return (p.quantity * (p.product.status == 3 || p.product.status == 4 ? p.product.promoPrice : p.product.price)) - // } const getPriceHTML = (/*prods*/) => { @@ -19,9 +16,6 @@ export function TotalProductsPrice(/*{ products }*/) { var tvq = 0; var total; - // prods.map((p) => { - // price += productTotal(p); - // }); tps = price * (tpsRate / 100); tvq = price * (tvqRate / 100); diff --git a/GrossesMitaines/grosses-mitaines-ui/src/pages/ReviewInvoice.js b/GrossesMitaines/grosses-mitaines-ui/src/pages/ReviewInvoice.js index 7ad297e..255f975 100644 --- a/GrossesMitaines/grosses-mitaines-ui/src/pages/ReviewInvoice.js +++ b/GrossesMitaines/grosses-mitaines-ui/src/pages/ReviewInvoice.js @@ -7,6 +7,7 @@ import { useNavigate } from "react-router-dom"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { CartContext } from "../components/Cart"; +import StripeContainer from "../components/StripeContainer" const ReviewInvoice = () => { @@ -28,26 +29,38 @@ const ReviewInvoice = () => { province: "", country: "", postalCode: "", - prodQuant: [] + prodQuant: [], }); + const [total, setTotal] = useState(-1); + useEffect(() => { const cookies = new Cookies(); const thisInvoice = cookies.get('invoice'); if (thisInvoice != null) { var dic = {}; if (cart.items.length > 0) { - cart.items.forEach((item) => - dic[item.id] = item.quantity + cart.items.forEach((item) => { + dic[item.id] = item.quantity; + } ) } - async function test() { + const tpsRate = 5; + const tvqRate = 9.975; - const json = JSON.stringify(dic); - console.log(await json); - } - test(); + var price = cart.getTotalCost(); + var tps = 0; + var tvq = 0; + var totalCost; + + tps = price * (tpsRate / 100); + tvq = price * (tvqRate / 100); + totalCost = price + tps + tvq; + totalCost = totalCost * 100; + totalCost = totalCost.toFixed(0); + + setTotal(totalCost); setThisInvoice((e) => { @@ -73,65 +86,12 @@ const ReviewInvoice = () => { } }, [cart]); - - // const handleAddOne = (id) => { - - // var modifiedPQ = prodQuant.filter((pq) => pq.id == id); - // var modifiedProd = prodQuant.filter((pq) => pq.product.id == id); - - // modifiedPQ.quantity++; - // modifiedProd.quantity = modifiedPQ.quantity; - - // setProdQuant([...(prodQuant.filter((pq) => pq.id !== id)), { ...modifiedPQ }].sort((a, b) => a.id - b.id)); - // setProducts([...(products.filter((pq) => pq.product.id !== id)), { ...modifiedProd }].sort((a, b) => a.product.id - b.product.id)); - - - // } - - // const handleRemoveOne = (id) => { - // var modifiedPQ = prodQuant.filter((pq) => pq.id == id); - // var modifiedProd = prodQuant.filter((pq) => pq.product.id == id); - - // if (modifiedPQ.quantity - 1 <= 0) { - // setProdQuant([...(prodQuant.filter((pq) => pq.id !== id))].sort((a, b) => a.id - b.id)); - // setProducts([...(products.filter((pq) => pq.product.id !== id))].sort((a, b) => a.product.id - b.product.id)); - // } - // else { - // modifiedPQ.quantity--; - // modifiedProd.quantity = modifiedPQ.quantity; - // setProdQuant([...(prodQuant.filter((pq) => pq.id !== id)), { ...modifiedPQ }].sort((a, b) => a.id - b.id)); - // setProducts([...(products.filter((pq) => pq.product.id !== id)), { ...modifiedProd }].sort((a, b) => a.product.id - b.product.id)); - // } - // } - - // const handleRemoveProduct = (id) => { - - // setProdQuant([...(prodQuant.filter((pq) => pq.id !== id))].sort((a, b) => a.id - b.id)); - // setProducts([...(products.filter((pq) => pq.product.id !== id))].sort((a, b) => a.product.id - b.product.id)); - // } - const handleModify = () => { navigate("/formulaire") } const handleConfirmer = async () => { - - // var dic = {}; - // if (cart.items.length > 0) { - // cart.items.forEach((item) => - // dic[item.id] = item.quantity - // ) - // } - // const json = JSON.stringify(dic); - // console.log(await json); - - // const json1 = JSON.stringify(cart.items); - // console.log(await json1); - - //setThisInvoice({ ...thisInvoice, prodQuant: dic }); - const json = JSON.stringify(thisInvoice); - console.log(json); const response = await fetch(`https://localhost:7292/api/Invoice`, { method: 'POST', @@ -167,69 +127,73 @@ const ReviewInvoice = () => { } return ( - -

Veuillez confirmer les informations ci-dessous!

- + <> + +

Veuillez confirmer les informations ci-dessous!

+ -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- {thisInvoice.appartment != null ? +
- + +
+
+ +
+
+ +
+
+
- : null - } -
-
-
- + +
+
+ +
+ {thisInvoice.appartment != null ? +
+ +
+ : null + } +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- +
+
-
- -
-
- -
-
-
- -
- + {/* - - - - - - + */} + + + + + + + + ); } diff --git a/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css b/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css index b1504b5..83721da 100644 --- a/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css +++ b/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css @@ -20,6 +20,44 @@ a { text-decoration: none; } +.Payment-btn-container { + display: flex; +} + +.Payment-btn { + margin: auto; + width: 20%; +} + +.FormGroup { + margin: 20px 15px 20px; + padding: 0; + border-style: none; + color: beige !important; + background-color: purple; + will-change: opacity, transform; + border-radius: 4px; +} + +.FormRow { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + margin-left: 15px; +} + +.StripeElement--webkit-autofill { + background: transparent !important; +} + +.StripeElement { + width: 100%; + padding: 11px 15px 11px 0; +} + + + .Contact { background-color: beige; text-align: center; @@ -770,7 +808,7 @@ a { .invoice-item-products h3 { text-align: center !important; - color:purple; + color: purple; font-weight: bold; background-color: beige; width: auto; @@ -831,12 +869,12 @@ a { } .invoice-buttons { - display:flex; - margin:5%; + display: flex; + margin: 5%; } .invoice-button { - margin:2%; + margin: 2%; width: 100%; align-content: center; } @@ -851,7 +889,7 @@ a { .confirmer-infos { text-align: center; - color:white; + color: white; font-weight: bold; } @@ -861,6 +899,12 @@ a { /* -------------------------------------------------------- */ @media(max-width:900px) { + .Payment-btn { + margin-top: 10px; + height: 70px; + width: 80%; + } + .invoice-item-container { display: block; }