Skip to content
This repository was archived by the owner on Jan 6, 2023. It is now read-only.

Commit 5c61ecc

Browse files
authored
Merge pull request #641 from blockstack/feature/payment-details-card
New payment card, switching apps, direct URLs, and more
2 parents db61737 + 672486d commit 5c61ecc

File tree

23 files changed

+620
-341
lines changed

23 files changed

+620
-341
lines changed

common/styles/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const theme = {
7272
accent: '#0CCABA'
7373
}),
7474
grey: Object.assign('#5B647C', {
75-
light: '#E6E9EE',
75+
light: '#F9F9FC',
7676
mid: '#7588A2',
7777
dark: '#142144'
7878
}),
@@ -94,7 +94,7 @@ const wrapperStyle = css`
9494
padding-right: 20px;
9595
${below.md`
9696
padding-left: 20px;
97-
padding-right: 20px;
97+
padding-right: 20px;
9898
`};
9999
`
100100

components/maker/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import Status from './status'
55
import Notification from './notification'
66
import { SidebarButton } from './styled'
77

8-
98
export default {
109
SidebarButton,
1110
PaymentDetails,

components/maker/modal.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import styled from 'styled-components'
55
import { CloseIcon } from '@components/svg/maker'
66

77
const customStyles = {
8-
content : {
8+
overlay: {
9+
// above headroom header library
10+
zIndex: 100
11+
},
12+
content: {
913
top: '50%',
1014
left: '50%',
1115
right: 'auto',
@@ -27,7 +31,7 @@ const CloseButtonContainer = styled.div`
2731

2832
const CloseButton = ({ handleClick }) => (
2933
<CloseButtonContainer onClick={handleClick}>
30-
<CloseIcon/>
34+
<CloseIcon />
3135
</CloseButtonContainer>
3236
)
3337

@@ -36,12 +40,11 @@ const MakerModal = ({ isOpen, handleClose, children }) => (
3640
isOpen={isOpen}
3741
onRequestClose={handleClose}
3842
style={customStyles}
39-
ariaHideApp={false}
43+
appElement={typeof document !== 'undefined' ? document.querySelector('#__next') : null}
4044
>
4145
<CloseButton handleClick={handleClose} />
4246
{children}
4347
</Modal>
4448
)
4549

46-
4750
export default MakerModal
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from 'react'
2+
import { Flex, Box, Type } from 'blockstack-ui'
3+
import { MakerCardHeader, MakerCardText, MakerButton, MakerField } from '../styled'
4+
5+
export const PaymentContainer = ({ children }) => (
6+
<Flex>
7+
<Box width={1} mt={0} as="form">
8+
{children}
9+
</Box>
10+
</Flex>
11+
)
12+
13+
export const PaymentHeader = MakerCardHeader
14+
15+
export const PaymentDescription = () => (
16+
<MakerCardText mb={5} mt={0}>
17+
This is where you will receive your App Mining payments.
18+
Currently, payments are made in Bitcoin (BTC). Payments will be made
19+
in Stacks (STX) in the future.
20+
</MakerCardText>
21+
)
22+
23+
export const PaymentHelpText = () => (
24+
<Type.p fontSize={12} mt={0} display="block">
25+
{"Don't"} have a Stacks address? <a href="https://wallet.blockstack.org" target="_blank" rel="noopener noreferrer">Download the Stacks wallet to get one</a>
26+
</Type.p>
27+
)
28+
29+
export const PaymentBtcField = props => (
30+
<MakerField
31+
name="btcAddress"
32+
label="Bitcoin Address"
33+
placeholder="Enter a Bitcoin address"
34+
{...props}
35+
/>
36+
)
37+
38+
export const PaymentStxField = props => (
39+
<MakerField
40+
name="stacksAddress"
41+
label="Stacks Address"
42+
placeholder="Enter a Stacks address"
43+
{...props}
44+
/>
45+
)
46+
47+
export const PaymentButton = ({ children, ...props }) => (
48+
<MakerButton type="button" mt={4} {...props}>
49+
{children}
50+
</MakerButton>
51+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { address, networks } from 'bitcoinjs-lib'
2+
import * as c32Check from 'c32check'
3+
import memoize from 'lodash/memoize'
4+
5+
export const validateBTC = memoize(addr => {
6+
try {
7+
address.toOutputScript(addr, networks.bitcoin)
8+
return true
9+
} catch (error) {
10+
return false
11+
}
12+
})
13+
14+
export const validateSTX = memoize(addr => {
15+
try {
16+
c32Check.c32addressDecode(addr)
17+
return true
18+
} catch (error) {
19+
return false
20+
}
21+
})

components/maker/payment/index.js

Lines changed: 58 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,75 @@
11
import React, { useState } from 'react'
2-
import { Flex, Box, Type } from 'blockstack-ui'
3-
import { address, networks } from 'bitcoinjs-lib'
4-
import * as c32Check from 'c32check'
5-
import Notification from '../notification'
6-
2+
import { savePaymentDetails } from '@stores/maker/actions'
3+
import { validateBTC, validateSTX } from './helpers'
74
import {
8-
MakerCardHeader,
9-
MakerCardText,
10-
MakerButton,
11-
MakerField
12-
} from '../styled'
13-
14-
const validateBTC = (addr) => {
15-
try {
16-
address.toOutputScript(addr, networks.bitcoin)
17-
return true
18-
} catch (error) {
19-
return false
20-
}
21-
}
22-
23-
const validateSTX = (addr) => {
24-
try {
25-
c32Check.c32addressDecode(addr)
26-
return true
27-
} catch (error) {
28-
return false
29-
}
30-
}
5+
PaymentContainer,
6+
PaymentHeader,
7+
PaymentDescription,
8+
PaymentHelpText,
9+
PaymentBtcField,
10+
PaymentStxField,
11+
PaymentButton
12+
} from './content'
3113

32-
const PaymentDetails = ({ app, apiServer, accessToken, user }) => {
14+
const PaymentDetails = ({ app, apiServer, accessToken, user, dispatch }) => {
3315
const [btcAddress, setBTCAddress] = useState(app.BTCAddress)
3416
const [stxAddress, setSTXAddress] = useState(app.stacksAddress)
35-
const [showNotification, setShowNotification] = useState(false)
36-
const [btcValid, setBtcValid] = useState(true)
37-
const [stxValid, setStxValid] = useState(true)
3817
const [saving, setSaving] = useState(false)
18+
const [hasAttemptedSaved, setHasAttemptedSaved] = useState(false)
19+
const [savedValues, setSavedValue] = useState({ btcAddress, stxAddress })
3920

40-
const notify = () => {
41-
setShowNotification(true)
42-
setTimeout(() => {
43-
setShowNotification(false)
44-
}, 10000)
45-
}
21+
const isSaved = (
22+
btcAddress === savedValues.btcAddress &&
23+
btcAddress !== '' &&
24+
stxAddress === savedValues.stxAddress &&
25+
stxAddress !== ''
26+
)
4627

4728
const save = async () => {
48-
let isValid = true
49-
if (!validateBTC(btcAddress)) {
50-
isValid = false
51-
setBtcValid(false)
52-
}
53-
if (!validateSTX(stxAddress)) {
54-
isValid = false
55-
setStxValid(false)
56-
}
57-
if (!isValid) {
58-
return
59-
} else {
60-
setBtcValid(true)
61-
setStxValid(true)
62-
}
29+
setHasAttemptedSaved(true)
30+
if (!validateBTC(btcAddress) || !validateSTX(stxAddress)) return
6331
setSaving(true)
64-
console.log(stxAddress)
65-
const response = await fetch(`${apiServer}/api/maker/apps?appId=${app.id}`, {
66-
method: 'POST',
67-
headers: new Headers({
68-
'Content-Type': 'application/json',
69-
authorization: `Bearer ${user.jwt}`
70-
}),
71-
body: JSON.stringify({
72-
BTCAddress: btcAddress,
73-
stacksAddress: stxAddress
74-
})
75-
})
76-
await response.json()
77-
notify()
32+
await savePaymentDetails({ apiServer, appId: app.id, jwt: user.jwt, btcAddress, stxAddress })(dispatch)
7833
setSaving(false)
34+
setSavedValue({ btcAddress, stxAddress })
35+
}
36+
37+
const buttonText = () => {
38+
if (saving) return 'Saving…'
39+
if (isSaved) return 'Saved'
40+
return 'Save'
41+
}
42+
43+
const createInputError = ({ validateFn, currencySymbol }) => addressHash => {
44+
if (!hasAttemptedSaved) return null
45+
if (!validateFn(addressHash)) return `Please enter a valid ${currencySymbol} address`
46+
return null
7947
}
48+
const getBtcError = createInputError({ validateFn: validateBTC, currencySymbol: 'BTC' })
49+
const getStxError = createInputError({ validateFn: validateSTX, currencySymbol: 'STX' })
8050

8151
return (
82-
<Flex>
83-
<Box width={1} mt={0}>
84-
<MakerCardHeader>Payment details</MakerCardHeader>
85-
{showNotification && <Notification message="Thanks! Your payment details have been updated." />}
86-
<MakerCardText mb={5} mt={0}>
87-
This is where you will receive your App Mining payments.
88-
Currently, payments are made in Bitcoin (BTC). Payments will be made
89-
in Stacks (STX) in the future.
90-
</MakerCardText>
91-
<MakerField
92-
name="btcAddress"
93-
label="Bitcoin Address"
94-
placeholder="Enter a Bitcoin address"
95-
onChange={(e) => setBTCAddress(e.target.value)}
96-
value={btcAddress || ''}
97-
error={!btcValid ? 'Please enter a valid BTC address' : null}
98-
/>
99-
<MakerField
100-
name="stacksAddress"
101-
label="Stacks Address"
102-
placeholder="Enter a Stacks address"
103-
onChange={(e) => setSTXAddress(e.target.value)}
104-
value={stxAddress || ''}
105-
error={!stxValid ? 'Please enter a valid STX address' : null}
106-
/>
107-
<Type.p fontSize={12} mt={0} display="block">
108-
{"Don't"} have a Stacks address? <a href="https://wallet.blockstack.org" target="_blank" rel="noopener noreferrer">Download the Stacks wallet to get one</a>
109-
</Type.p>
110-
<MakerButton mt={4} disabled={saving} onClick={() => save({ btcAddress, stxAddress, apiServer, accessToken })}>
111-
{saving ? 'Saving...' : 'Save'}
112-
</MakerButton>
113-
</Box>
114-
</Flex>
52+
<PaymentContainer>
53+
<PaymentHeader>Payment details</PaymentHeader>
54+
<PaymentDescription />
55+
<PaymentBtcField
56+
onChange={e => setBTCAddress(e.target.value)}
57+
value={btcAddress || ''}
58+
error={getBtcError(btcAddress)}
59+
/>
60+
<PaymentStxField
61+
onChange={e => setSTXAddress(e.target.value)}
62+
value={stxAddress || ''}
63+
error={getStxError(stxAddress)}
64+
/>
65+
<PaymentHelpText/>
66+
<PaymentButton
67+
disabled={isSaved || saving}
68+
onClick={() => save({ btcAddress, stxAddress, apiServer, accessToken })}
69+
>
70+
{buttonText()}
71+
</PaymentButton>
72+
</PaymentContainer>
11573
)
11674
}
11775

components/maker/styled.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ export const MakerContainer = ({ children }) => (
5454
</Flex>
5555
)
5656

57+
export const MakerTitle = styled(Type.h2)`
58+
display: block;
59+
font-weight: 500;
60+
font-size: 24px;
61+
line-height: 28px;
62+
color: #0F1117;
63+
margin-bottom: 16px;
64+
`
5765

5866
export const MakerCardHeader = styled(Type.h2)`
5967
font-weight: 500;

components/page/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { StyledPage } from './styled'
77

88
const Page = ({ isErrorPage = false, children, admin = false, wrap, innerPadding = [2, 0], ...rest }) => (
99
<StyledPage {...rest}>
10-
<TopBar isErrorPage={isErrorPage} admin={admin} wrap={rest.wrap} />
10+
<TopBar isErrorPage={isErrorPage} admin={admin} wrap={wrap} />
1111
<StyledPage.Section flexDirection={['column']} alignItems="center" pt={[3, 4]} px={innerPadding}>
1212
{children}
1313
</StyledPage.Section>

components/submit/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react'
2+
import Link from 'next/link'
3+
import { Type, Box, Button } from 'blockstack-ui'
4+
5+
const SuccessCard = ({ isAppMiningEligible }) => (
6+
<Box width="100%" textAlign="center">
7+
<Box pb={6} width="100%">
8+
<Type mx="auto" fontSize={5} fontWeight="bold">
9+
Success!
10+
</Type>
11+
</Box>
12+
<Box mx="auto">
13+
<Type display="block">
14+
Thanks for your submission! Your app will need to be approved before being public on app.co.
15+
</Type>
16+
{isAppMiningEligible && (
17+
<>
18+
<Type my={3} display="block">
19+
To update your app&apos;s details and enroll in App Mining, visit our Maker Portal
20+
</Type>
21+
<Link href={{ pathname: '/maker' }} passHref>
22+
<Button is="a" href="/" color="white !important">
23+
Go to the Maker Portal
24+
</Button>
25+
</Link>
26+
</>
27+
)}
28+
</Box>
29+
</Box>
30+
)
31+
32+
export default SuccessCard

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@mdx-js/tag": "^0.15.0",
3838
"@next/bundle-analyzer": "^9.0.6",
3939
"@next/mdx": "^9.0.6",
40+
"@types/react-redux": "^7.1.5",
4041
"accounting": "^0.4.1",
4142
"async": "^2.6.0",
4243
"bitcoinjs-lib": "^5.0.5",
@@ -63,6 +64,7 @@
6364
"grid-styled": "5.0.2",
6465
"intersection-observer": "^0.5.1",
6566
"isomorphic-unfetch": "^3.0.0",
67+
"js-cookie": "^2.2.1",
6668
"lodash": "^4.17.11",
6769
"lodash.debounce": "^4.0.8",
6870
"lru-cache": "^4.1.3",

0 commit comments

Comments
 (0)