mirror of
https://github.com/KevinMidboe/planetposen.git
synced 2025-10-29 17:50:32 +00:00
Implemented payments with stripe.
This commit is contained in:
@@ -97,6 +97,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="checkout-actions margin-top--lg">
|
<div class="checkout-actions margin-top--lg">
|
||||||
<applePay />
|
<applePay />
|
||||||
|
|
||||||
|
<stripe />
|
||||||
|
|
||||||
<Button color="green" :small="true" :scaleRotate="true">Gå til kassen</Button>
|
<Button color="green" :small="true" :scaleRotate="true">Gå til kassen</Button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -110,13 +113,15 @@ import store from '@/store';
|
|||||||
import Picker from '@/components/ui/Picker'
|
import Picker from '@/components/ui/Picker'
|
||||||
import Button from '@/components/ui/Button'
|
import Button from '@/components/ui/Button'
|
||||||
import applePay from '@/components/ui/applePay';
|
import applePay from '@/components/ui/applePay';
|
||||||
|
import stripe from '@/components/stripe';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Cart',
|
name: 'Cart',
|
||||||
components: {
|
components: {
|
||||||
Picker,
|
Picker,
|
||||||
Button,
|
Button,
|
||||||
applePay
|
applePay,
|
||||||
|
stripe
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
cartInventory() {
|
cartInventory() {
|
||||||
|
|||||||
166
frontend/components/stripe.vue
Normal file
166
frontend/components/stripe.vue
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div ref="confirmDiag" class="feedback-text"></div>
|
||||||
|
<div class="card">
|
||||||
|
<div ref="card"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button @click="pay" :small="true">Pay</Button>
|
||||||
|
|
||||||
|
<div class="applePay">
|
||||||
|
<div ref="paymentRequestButton"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { loadStripe } from '@stripe/stripe-js';
|
||||||
|
import Button from '@/components/ui/Button';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Button
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
clientSecret: null,
|
||||||
|
card: null,
|
||||||
|
stripe: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.stripe = await loadStripe('pk_test_YiU5HewgBoClZCwHdhXhTxUn')
|
||||||
|
this.mountCard();
|
||||||
|
this.mountApplePay();
|
||||||
|
|
||||||
|
this.makeIntent();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
pay() {
|
||||||
|
this.stripe.confirmCardPayment(this.clientSecret, {
|
||||||
|
payment_method: {
|
||||||
|
card: this.card,
|
||||||
|
billing_details: {
|
||||||
|
name: 'Kevin Testost'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
if (result.error) {
|
||||||
|
console.log('Error confirmPayment:', result.error.message)
|
||||||
|
} else {
|
||||||
|
if (result.paymentIntent.status === 'succeeded') {
|
||||||
|
this.$refs.confirmDiag.innerText = 'Confirmed transaction!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
makeIntent() {
|
||||||
|
fetch('/api/stripe/create-payment-intent', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(resp => resp.json())
|
||||||
|
.then(data => this.clientSecret = data.clientSecret)
|
||||||
|
},
|
||||||
|
mountApplePay() {
|
||||||
|
const paymentRequest = this.stripe.paymentRequest({
|
||||||
|
country: 'NO',
|
||||||
|
currency: 'nok',
|
||||||
|
total: {
|
||||||
|
label: 'Demo total',
|
||||||
|
amount: 1009
|
||||||
|
},
|
||||||
|
// requestShipping: true,
|
||||||
|
requestPayerName: true,
|
||||||
|
requestPayerEmail: true
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('payment request:', paymentRequest);
|
||||||
|
|
||||||
|
const elements = this.stripe.elements();
|
||||||
|
const prButton = elements.create('paymentRequestButton', {
|
||||||
|
paymentRequest
|
||||||
|
});
|
||||||
|
|
||||||
|
paymentRequest.on('paymentmethod', ev => {
|
||||||
|
console.log('ev from paymentmethods:', ev)
|
||||||
|
this.stripe.confirmCardPayment(this.clientSecret,
|
||||||
|
{ payment_method: ev.paymentMethod.id },
|
||||||
|
{ handleActions: false }
|
||||||
|
).then(confirmResult => {
|
||||||
|
if (confirmResult.error) {
|
||||||
|
console.log('confirm error:', confirmResult.error);
|
||||||
|
ev.complete('fail');
|
||||||
|
} else {
|
||||||
|
console.log('confirm success:', confirmResult)
|
||||||
|
ev.complete('success')
|
||||||
|
this.stripe.confirmCardPayment(this.clientSecret)
|
||||||
|
.then(result => {
|
||||||
|
console.log('finall response from stripe:', result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
paymentRequest.canMakePayment()
|
||||||
|
.then(result => {
|
||||||
|
if (result) {
|
||||||
|
prButton.mount(this.$refs.paymentRequestButton)
|
||||||
|
} else
|
||||||
|
console.error('unable to load', result);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mountCard() {
|
||||||
|
const elements = this.stripe.elements();
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
base: {
|
||||||
|
color: '#32325d',
|
||||||
|
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
|
||||||
|
fontSmoothing: 'antialiased',
|
||||||
|
fontSize: '16px',
|
||||||
|
'::placeholder': {
|
||||||
|
color: '#aab7c4'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
invalid: {
|
||||||
|
color: '#fa755a',
|
||||||
|
iconColor: '#fa755a'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.card = elements.create('card', { style: style });
|
||||||
|
|
||||||
|
this.card.mount(this.$refs.card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
background-color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: 2px solid var(--background-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-text {
|
||||||
|
color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.applePay {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -13,12 +13,14 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "~7.2",
|
"@babel/polyfill": "~7.2",
|
||||||
|
"@stripe/stripe-js": "^1.8.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"mongoose": "^5.9.24",
|
"mongoose": "^5.9.24",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"node-sass": "^4.13.0",
|
"node-sass": "^4.13.0",
|
||||||
|
"stripe": "^8.76.0",
|
||||||
"vue": "~2.6",
|
"vue": "~2.6",
|
||||||
"vue-router": "~3.0",
|
"vue-router": "~3.0",
|
||||||
"vuex": "^3.1.1"
|
"vuex": "^3.1.1"
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ const PORT = 30010;
|
|||||||
|
|
||||||
const productsController = require('./controllers/product.js');
|
const productsController = require('./controllers/product.js');
|
||||||
const variationsController = require('./controllers/variation.js');
|
const variationsController = require('./controllers/variation.js');
|
||||||
|
const applePayController = require('./controllers/applePay.js');
|
||||||
|
const stripeController = require('./controllers/stripe.js');
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
// app.use(express.urlencoded());
|
// app.use(express.urlencoded());
|
||||||
@@ -24,6 +26,10 @@ router.post('/product', productsController.addNewProduct)
|
|||||||
|
|
||||||
router.post('/variation/:id', variationsController.addNewVariationToProduct);
|
router.post('/variation/:id', variationsController.addNewVariationToProduct);
|
||||||
|
|
||||||
|
router.post('/applepay/validateSession', applePayController.validateSession)
|
||||||
|
router.post('/applepay/pay', applePayController.pay)
|
||||||
|
router.post('/stripe/create-payment-intent', stripeController.createPaymentIntent)
|
||||||
|
|
||||||
app.use("/public", express.static(path.join(__dirname, "public")));
|
app.use("/public", express.static(path.join(__dirname, "public")));
|
||||||
app.use("/dist", express.static(path.join(__dirname, "/../public/dist")));
|
app.use("/dist", express.static(path.join(__dirname, "/../public/dist")));
|
||||||
app.use('/.well-known', express.static(path.join(__dirname, "/../frontend/assets/well-known")));
|
app.use('/.well-known', express.static(path.join(__dirname, "/../frontend/assets/well-known")));
|
||||||
|
|||||||
7
server/config.example.js
Normal file
7
server/config.example.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
module.exports = {
|
||||||
|
stripe: {
|
||||||
|
publicKey: '',
|
||||||
|
secretKey: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
22
server/controllers/stripe.js
Normal file
22
server/controllers/stripe.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const config = require('../config')
|
||||||
|
const Stripe = require('stripe')
|
||||||
|
const stripe = Stripe(config.stripe.secretKey)
|
||||||
|
|
||||||
|
const createPaymentIntent = async (req, res) => {
|
||||||
|
const { items, currency } = req.body;
|
||||||
|
|
||||||
|
const paymentIntent = await stripe.paymentIntents.create({
|
||||||
|
amount: 1009,
|
||||||
|
currency: 'NOK'
|
||||||
|
})
|
||||||
|
console.log('created payment intent:', paymentIntent);
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
publishableKey: config.stripe.publicKey,
|
||||||
|
clientSecret: paymentIntent.client_secret
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createPaymentIntent
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user