Skip to content

Commit 4cb75b5

Browse files
committed
Billing and payment added
1 parent 9745f4e commit 4cb75b5

File tree

5 files changed

+91
-26
lines changed

5 files changed

+91
-26
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
.DS_Store
22
node_modules
33
npm-debug.log
4-
.env
4+
.env*

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"private": true,
3-
"version": "1.0.9",
3+
"version": "1.1.0",
44
"name": "dropstack-dashboard",
55
"description": "DropStack dashboard.",
66
"engines": {
@@ -19,7 +19,7 @@
1919
"export:dev": "NODE_ENV=production reunify export -d",
2020
"export:package": "NODE_ENV=production reunify export -p",
2121
"export:package:dev": "NODE_ENV=production reunify export -p -d",
22-
"dev": "PORT=8080 NODE_ENV=development dotenv -e .env reunify serve",
23-
"start": "PORT=80 NODE_ENV=production reunify serve --silent"
22+
"dev": "PORT=8080 NODE_ENV=development dotenv -e .env-dev reunify serve",
23+
"start": "PORT=80 NODE_ENV=production dotenv -e .env-prod reunify serve --silent"
2424
}
2525
}

pages/Account.js

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ const BillingCardButton = styled.button`
3333
border-radius: 0px;
3434
background-color: white;
3535
cursor: pointer;
36+
:disabled {
37+
color: #dddddd;
38+
border: 1px solid #dddddd;
39+
cursor: not-allowed;
40+
}
3641
`
3742

3843
const BillingCardErrorMessage = styled.div`
@@ -42,10 +47,20 @@ const BillingCardErrorMessage = styled.div`
4247
font-size: 11px;
4348
`
4449

50+
const BillingCardSuccessMessage = styled.div`
51+
color: green;
52+
width: 300px;
53+
padding: 5px;
54+
font-size: 11px;
55+
`
56+
4557
export default class Account extends React.Component {
4658
state = {
47-
error: '',
48-
token: '',
59+
registerCustomerError: '',
60+
registerCustomerSuccess: '',
61+
chargeError: '',
62+
chargeSuccess: '',
63+
account: null,
4964
}
5065

5166
static async getInitialProps (req, res, ctx) {
@@ -55,12 +70,13 @@ export default class Account extends React.Component {
5570
.then(data => ({account: data, token}))
5671
}
5772

58-
addCard () {
59-
const cardData = {
73+
registerCustomer () {
74+
const customerData = {
6075
number: this.number.value,
6176
exp_month: this.exp_month.value,
6277
exp_year: this.exp_year.value,
6378
cvc: this.cvc.value,
79+
name: this.name.value,
6480
}
6581

6682
/*
@@ -70,20 +86,31 @@ export default class Account extends React.Component {
7086
123
7187
*/
7288

73-
fetch('/payment', {credentials: 'include', method: 'POST', body: JSON.stringify(cardData), headers: {'Content-Type': 'application/json'}})
89+
fetch('/payment', {credentials: 'include', method: 'POST', body: JSON.stringify(customerData), headers: {'Content-Type': 'application/json'}})
7490
.then(response => response.json())
7591
.then(data => {
76-
if(data.error) return this.setState({error: data.error})
77-
console.log(data)
78-
this.setState({
79-
error: '',
80-
token: data.token,
81-
})
92+
if(data.error) return this.setState({registerCustomerError: data.error})
93+
this.setState({registerCustomerError: '', registerCustomerSuccess: 'Successful registrated', account: data})
8294
})
83-
.catch(err => this.setState({error: err.message}))
95+
.catch(err => this.setState({registerCustomerError: err.message, registerCustomerSuccess: ''}))
96+
}
97+
98+
chargeAmount () {
99+
const changeData = {amount: this.amount.value}
100+
101+
fetch('/charge', {credentials: 'include', method: 'POST', body: JSON.stringify(changeData), headers: {'Content-Type': 'application/json'}})
102+
.then(response => response.json())
103+
.then(data => {
104+
if(data.error) return this.setState({chargeError: data.error, chargeSuccess: ''})
105+
this.setState({chargeError: '', chargeSuccess: 'Successful charged'})
106+
})
107+
.catch(err => this.setState({chargeError: err.message, chargeSuccess: ''}))
84108
}
85109

86110
render() {
111+
const account = this.state.account || this.props.account || {}
112+
const payment = account.payment || {}
113+
const source = ((payment.sources || {}).data || []).find(x => x.id === payment.default_source) || {};
87114
return (
88115
<AccountContainer>
89116
<h2># account</h2>
@@ -93,14 +120,30 @@ export default class Account extends React.Component {
93120
<div><strong>JSON Web Token&nbsp;:</strong> {this.props.token}</div>
94121
</div>
95122
<h2># billing</h2>
96-
<BillingCardInput type="text" innerRef={x => this.number = x} placeholder="number" />
97-
<BillingCardInput type="text" innerRef={x => this.exp_month = x} placeholder="expiration month" />
98-
<BillingCardInput type="text" innerRef={x => this.exp_year = x} placeholder="expiration year" />
99-
<BillingCardInput type="text" innerRef={x => this.cvc = x} placeholder="cvc" />
100-
<BillingCardButton onClick={() => this.addCard()}>Add Card</BillingCardButton>
123+
<BillingCardInput type="text" innerRef={x => this.name = x} placeholder="Name" defaultValue={source.name} />
124+
<BillingCardInput type="text" innerRef={x => this.number = x} placeholder="Number" defaultValue={source.last4 ? `XXXX-XXXX-XXXX-${source.last4}` : ''} />
125+
<BillingCardInput type="number" innerRef={x => this.exp_month = x} placeholder="Expiration month" defaultValue={source.exp_month} />
126+
<BillingCardInput type="number" innerRef={x => this.exp_year = x} placeholder="Expiration year" defaultValue={source.exp_year} />
127+
<BillingCardInput type="number" innerRef={x => this.cvc = x} placeholder="CVC" />
128+
<BillingCardButton onClick={() => this.registerCustomer()}>Register</BillingCardButton>
129+
{
130+
this.state.registerCustomerError &&
131+
<BillingCardErrorMessage>{this.state.registerCustomerError}</BillingCardErrorMessage>
132+
}
133+
{
134+
this.state.registerCustomerSuccess &&
135+
<BillingCardSuccessMessage>{this.state.registerCustomerSuccess}</BillingCardSuccessMessage>
136+
}
137+
<h2># payment</h2>
138+
<BillingCardInput type="number" innerRef={x => this.amount = x} placeholder="Amount in EUR" />
139+
<BillingCardButton disabled={!payment.default_source} onClick={() => this.chargeAmount()}>Fair Pay</BillingCardButton>
140+
{
141+
this.state.chargeError &&
142+
<BillingCardErrorMessage>{this.state.chargeError}</BillingCardErrorMessage>
143+
}
101144
{
102-
this.state.error &&
103-
<BillingCardErrorMessage>{this.state.error}</BillingCardErrorMessage>
145+
this.state.chargeSuccess &&
146+
<BillingCardSuccessMessage>{this.state.chargeSuccess}</BillingCardSuccessMessage>
104147
}
105148
</AccountContainer>
106149
)

pages/Charge.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export default {
2+
async getJSON(req, res, ctx) {
3+
const stripe = require('stripe')(ctx.env.STRIPE_SECRET_KEY)
4+
const jwt = require('jsonwebtoken')
5+
const PouchDB = require('pouchdb')
6+
7+
const token = req.universalCookies.get('token')
8+
const {sub} = jwt.decode(token)
9+
const usersDB = new PouchDB(`${ctx.env.BASE_URL}/users`)
10+
11+
return usersDB.get(sub)
12+
.then(data => {
13+
const charge = {...req.body}
14+
charge.customer = data.payment.id
15+
charge.currency = 'eur'
16+
charge.amount = parseInt(charge.amount) * 100
17+
return stripe.charges.create(charge)
18+
})
19+
.catch(err => ({error: err.message}))
20+
}
21+
}

pages/Payment.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ export default {
44
const jwt = require('jsonwebtoken')
55
const PouchDB = require('pouchdb')
66

7-
const card = req.body
7+
const card = {...req.body, object: 'card'}
88
const token = req.universalCookies.get('token')
99
const {sub} = jwt.decode(token)
1010
const usersDB = new PouchDB(`${ctx.env.BASE_URL}/users`)
1111

1212
return Promise.all([
13-
stripe.tokens.create({card}),
13+
stripe.customers.create({card, email: sub}),
1414
usersDB.get(sub),
1515
])
16-
.then(data => usersDB.put(Object.assign({}, data[1], {token: data[0].id, card: data[0].card})).then(() => ({token: data[0].id})))
16+
.then(data => Object.assign({}, data[1], {payment: data[0]}))
17+
.then(data => usersDB.put(data).then(() => data))
1718
.catch(err => ({error: err.message}))
1819
}
1920
}

0 commit comments

Comments
 (0)