Skip to content
Next
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Minds Mobile
Project
Project
Details
Activity
Releases
Cycle Analytics
Insights
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
204
Issues
204
List
Boards
Labels
Service Desk
Milestones
Merge Requests
13
Merge Requests
13
Security & Compliance
Security & Compliance
Dependency List
Packages
Packages
List
Container Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Minds
Minds Mobile
Commits
f8095bdf
Commit
f8095bdf
authored
11 hours ago
by
Martin Santangelo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP: payment selector, btc payment, wire refactor
parent
bc618baf
epic/wire-37
1 merge request
!325
WIP: [Sprint/ModestMonkey] wire epic 37
Changes
10
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
439 additions
and
249 deletions
+439
-249
en.json
locales/en.json
+1
-0
Common.js
src/styles/Common.js
+11
-9
Components.js
src/styles/Components.js
+1
-1
FabScreen.js
src/wire/FabScreen.js
+116
-196
WireService.js
src/wire/WireService.js
+16
-11
WireStore.js
src/wire/WireStore.js
+84
-26
BtcPayment.js
src/wire/methods/BtcPayment.js
+74
-0
PaymentMethodIcon.js
src/wire/methods/PaymentMethodIcon.js
+34
-0
PaymentMethodSelector.js
src/wire/methods/PaymentMethodSelector.js
+95
-0
SubscriptionTierCarousel.js
src/wire/tiers/SubscriptionTierCarousel.js
+7
-6
No files found.
locales/en.json
View file @
f8095bdf
...
...
@@ -557,6 +557,7 @@
},
"wire"
:{
"amountMonth"
:
"{{amount}}/month"
,
"noBtcAddress"
:
"This channel has not configured their Bitcoin address yet"
,
"amountMonthDescription"
:
"THIS POST CAN ONLY BE SEEN BY SUPPORTERS WHO WIRE {{amount}}/MONTH TO @{{name}}"
,
"weHaveReceivedYourTransaction"
:
"We've received your transaction"
,
"pleaseTryUnlockingMessage"
:
"Please try unlocking this post after it gets processed. We estimate it may take around 5 minutes."
,
...
...
This diff is collapsed.
Click to expand it.
src/styles/Common.js
View file @
f8095bdf
...
...
@@ -22,26 +22,26 @@ export const CommonStyle = StyleSheet.create({
alignContent
:
'
center
'
,
},
centered
:
{
alignContent
:
'
center
'
,
alignItems
:
'
center
'
,
alignSelf
:
'
center
'
,
justifyContent
:
'
center
'
,
alignContent
:
'
center
'
,
alignSelf
:
'
center
'
},
columnAlignCenter
:
{
flexDirection
:
'
column
'
,
alignItems
:
'
center
'
,
flexDirection
:
'
column
'
,
},
columnAlignStart
:
{
flexDirection
:
'
column
'
,
alignItems
:
'
flex-start
'
,
flexDirection
:
'
column
'
,
},
columnAlignEnd
:
{
flexDirection
:
'
column
'
,
alignItems
:
'
flex-end
'
,
flexDirection
:
'
column
'
,
},
columnStretch
:
{
flexDirection
:
'
column
'
,
alignItems
:
'
stretch
'
,
flexDirection
:
'
column
'
,
},
rowJustifyEnd
:
{
flexDirection
:
'
row
'
,
...
...
@@ -74,12 +74,11 @@ export const CommonStyle = StyleSheet.create({
fillFlex
:
{
flexGrow
:
1
,
},
// color
colorWhite
:
{
color
:
'
white
'
color
:
'
#FFFFFF
'
},
colorBlack
:
{
color
:
'
black
'
color
:
'
#000000
'
},
colorLight
:
{
color
:
colors
.
light
...
...
@@ -158,6 +157,9 @@ export const CommonStyle = StyleSheet.create({
borderLight
:
{
borderColor
:
colors
.
light
},
borderLightGreyed
:
{
borderColor
:
colors
.
lightGreyed
},
borderSecondary
:
{
borderColor
:
colors
.
secondary
},
...
...
This diff is collapsed.
Click to expand it.
src/styles/Components.js
View file @
f8095bdf
...
...
@@ -70,7 +70,7 @@ export const ComponentsStyle = StyleSheet.create({
margin
:
4
,
padding
:
4
,
alignItems
:
'
center
'
,
borderRadius
:
15
,
borderRadius
:
20
,
borderWidth
:
1
,
},
bluebutton
:
{
...
...
This diff is collapsed.
Click to expand it.
src/wire/FabScreen.js
View file @
f8095bdf
This diff is collapsed.
Click to expand it.
src/wire/WireService.js
View file @
f8095bdf
// @flow
import
api
from
'
./../common/services/api.service
'
;
import
i18n
from
'
../common/services/i18n.service
'
;
import
BlockchainWireService
from
'
../blockchain/services/BlockchainWireService
'
;
...
...
@@ -13,9 +14,9 @@ class WireService {
* Unlock an activity
* @param {string} guid
*/
unlock
(
guid
)
{
unlock
(
guid
:
string
):
Promise
<
any
>
{
return
api
.
get
(
`api/v1/wire/threshold/
${
guid
}
`
)
.
then
((
response
)
=>
{
.
then
((
response
:
any
):
any
=>
{
if
(
response
.
hasOwnProperty
(
'
activity
'
))
{
return
response
.
activity
;
}
else
if
(
response
.
hasOwnProperty
(
'
entity
'
))
{
...
...
@@ -29,7 +30,7 @@ class WireService {
* Get overview
* @param {string} guid
*/
overview
(
guid
)
{
overview
(
guid
:
string
):
Promise
<
any
>
{
return
api
.
get
(
`api/v1/wire/sums/overview/
${
guid
}
?merchant=1`
);
}
...
...
@@ -37,7 +38,7 @@ class WireService {
* Get user rewards
* @param {string} guid
*/
userRewards
(
guid
)
{
userRewards
(
guid
:
string
):
Promise
<
any
>
{
return
api
.
get
(
`api/v1/wire/rewards/
${
guid
}
/entity`
);
}
...
...
@@ -45,14 +46,14 @@ class WireService {
* Get rewards
* @param {string} guid
*/
rewards
(
guid
)
{
rewards
(
guid
:
string
):
Promise
<
any
>
{
return
api
.
get
(
`api/v1/wire/rewards/
${
guid
}
`
)
.
then
(
rewards
=>
{
.
then
(
(
rewards
:
any
):
any
=>
{
rewards
=
(
rewards
.
wire_rewards
)
?
rewards
.
wire_rewards
.
rewards
:
null
if
(
rewards
)
{
// map types
for
(
let
type
in
rewards
)
{
rewards
[
type
]
=
rewards
[
type
].
map
((
reward
)
=>
{
rewards
[
type
]
=
rewards
[
type
].
map
((
reward
)
:
any
=>
{
reward
.
type
=
type
;
return
reward
;
});
...
...
@@ -66,7 +67,7 @@ class WireService {
* Send wire
* @param {object} opts
*/
async
send
(
opts
)
{
async
send
(
opts
)
:
Promise
<
any
>
{
const
payload
=
await
this
.
getTransactionPayloads
(
opts
);
if
(
!
payload
)
{
...
...
@@ -78,7 +79,7 @@ class WireService {
method
:
'
tokens
'
,
amount
:
opts
.
amount
,
recurring
:
!!
opts
.
recurring
}).
then
(
result
=>
{
}).
then
(
(
result
:
any
):
any
=>
{
result
.
payload
=
payload
;
return
result
;
});
...
...
@@ -88,8 +89,12 @@ class WireService {
* Get transaction payloads
* @param {object} opts
*/
async
getTransactionPayloads
(
opts
)
{
const
payload
=
await
BlockchainWalletService
.
selectCurrent
(
i18n
.
t
(
'
wire.selectWalletMessage
'
),
{
signable
:
true
,
offchain
:
true
,
buyable
:
true
,
confirmTokenExchange
:
opts
.
amount
});
async
getTransactionPayloads
(
opts
:
Object
):
any
{
if
(
opts
.
currency
==
'
tokens
'
)
{
const
payload
=
await
BlockchainWalletService
.
selectCurrent
(
i18n
.
t
(
'
wire.selectWalletMessage
'
),
{
signable
:
true
,
offchain
:
true
,
buyable
:
true
,
confirmTokenExchange
:
opts
.
amount
});
}
if
(
!
payload
||
payload
.
cancelled
)
{
return
;
...
...
This diff is collapsed.
Click to expand it.
src/wire/WireStore.js
View file @
f8095bdf
// @flow
import
{
observable
,
action
}
from
'
mobx
'
import
{
Alert
}
from
'
react-native
'
;
import
wireService
from
'
./WireService
'
;
import
currency
from
'
../common/helpers/currency
'
;
import
i18n
from
'
../common/services/i18n.service
'
;
export
type
PayloadType
=
|
'
onchain
'
|
'
offchain
'
|
'
usd
'
|
'
eth
'
|
'
erc20
'
|
'
btc
'
;
/**
* Wire store
*/
class
WireStore
{
@
observable
currency
=
'
tokens
'
;
@
observable
amount
=
1
;
@
observable
sending
=
false
;
@
observable
.
shallow
owner
=
null
;
@
observable
recurring
=
false
;
@
observable
showBtc
=
false
;
@
observable
loaded
=
false
;
@
observable
errors
=
[];
guid
=
null
;
setGuid
(
guid
)
{
this
.
guid
=
guid
;
@
action
setShowBtc
=
(
value
:
boolean
)
=>
{
this
.
showBtc
=
value
;
}
@
action
setCurrency
(
value
)
{
setCurrency
=
(
value
:
string
)
=>
{
this
.
currency
=
value
;
// only tokens and usd can be recurring
if
(
this
.
currency
!==
'
tokens
'
&&
this
.
currency
!==
'
usd
'
)
{
this
.
recurring
=
false
;
}
this
.
validate
();
}
@
action
setAmount
(
val
)
{
setAmount
(
val
:
number
)
{
this
.
amount
=
val
;
this
.
validate
();
}
@
action
setTier
=
(
tier
)
=>
{
setTier
=
(
tier
:
any
)
=>
{
this
.
amount
=
tier
.
amount
;
if
(
tier
.
currency
)
this
.
currency
=
tier
.
currency
;
if
(
tier
.
currency
)
{
this
.
setCurrency
(
tier
.
currency
);
}
else
{
this
.
validate
();
}
}
@
action
setOwner
(
owner
)
{
setOwner
(
owner
:
any
)
{
this
.
owner
=
owner
;
}
loadUser
(
guid
)
{
return
wireService
.
userRewards
(
guid
)
.
then
(
owner
=>
{
this
.
setOwner
(
owner
);
return
owner
;
});
async
loadUserRewards
():
Promise
<
any
>
{
const
owner
=
await
wireService
.
userRewards
(
this
.
owner
.
guid
);
const
{
merchant
,
eth_wallet
,
wire_rewards
,
sums
}
=
owner
;
if
(
this
.
owner
)
{
this
.
owner
.
merchant
=
merchant
;
this
.
owner
.
eth_wallet
=
eth_wallet
;
this
.
owner
.
wire_rewards
=
wire_rewards
;
this
.
owner
.
sums
=
sums
;
}
this
.
setLoaded
(
true
);
return
owner
;
}
round
(
number
,
precision
)
{
@
action
setLoaded
(
value
:
boolean
)
{
this
.
loaded
=
value
;
}
round
(
number
:
number
,
precision
:
number
):
number
{
const
factor
=
Math
.
pow
(
10
,
precision
);
const
tempNumber
=
number
*
factor
;
const
roundedTempNumber
=
Math
.
round
(
tempNumber
);
...
...
@@ -64,16 +96,32 @@ class WireStore {
/**
* Get formated amount
*/
formatAmount
(
amount
)
{
formatAmount
(
amount
:
number
):
string
{
return
amount
.
toLocaleString
(
'
en-US
'
)
+
'
tokens
'
;
}
/**
* Validate payment
*/
@
action
validate
()
{
//TODO: implement wire validation
this
.
errors
=
[];
switch
(
this
.
currency
)
{
case
'
btc
'
:
if
(
this
.
owner
&&
!
this
.
owner
.
btc_address
)
{
this
.
errors
.
push
(
i18n
.
t
(
'
wire.noBtcAddress
'
));
}
break
;
}
if
(
this
.
amount
<=
0
)
{
this
.
errors
.
push
(
i18n
.
t
(
'
boosts.errorAmountSholdbePositive
'
));
}
}
@
action
setRecurring
(
recurring
)
{
setRecurring
(
recurring
:
boolean
)
{
this
.
recurring
=
!!
recurring
;
}
...
...
@@ -85,13 +133,19 @@ class WireStore {
/**
* Confirm and Send wire
*/
async
send
()
{
@
action
async
send
():
Promise
<
any
>
{
if
(
this
.
sending
)
{
return
;
}
let
done
;
// for btc we only show the btc component
if
(
this
.
currency
===
'
btc
'
)
{
return
this
.
setShowBtc
(
true
);
}
try
{
this
.
sending
=
true
;
...
...
@@ -99,7 +153,8 @@ class WireStore {
amount
:
this
.
amount
,
guid
:
this
.
guid
,
owner
:
this
.
owner
,
recurring
:
this
.
recurring
recurring
:
this
.
recurring
,
currency
:
this
.
currency
});
this
.
stopSending
();
...
...
@@ -119,10 +174,13 @@ class WireStore {
@
action
reset
()
{
this
.
amount
=
1
;
this
.
showBtc
=
false
;
this
.
currency
=
'
tokens
'
;
this
.
sending
=
false
;
this
.
owner
=
null
;
this
.
recurring
=
false
;
this
.
guid
=
null
;
this
.
loaded
=
false
;
this
.
errors
=
[];
}
}
...
...
This diff is collapsed.
Click to expand it.
src/wire/methods/BtcPayment.js
0 → 100644
View file @
f8095bdf
// @flow
import
*
as
React
from
'
react
'
import
{
View
,
Text
,
Linking
}
from
'
react-native
'
;
import
QRCode
from
'
react-native-qrcode-svg
'
;
import
{
CommonStyle
as
CS
}
from
'
../../styles/Common
'
;
import
viewportPercentage
from
'
../../common/helpers/viewportPercentage
'
;
import
Button
from
'
../../common/components/Button
'
;
import
i18nService
from
'
../../common/services/i18n.service
'
;
type
PropsType
=
{
address
:
string
,
amount
:
number
,
onCancel
:
?
Function
};
/**
* Btc Payment
*/
export
default
class
BtcPayment
extends
React
.
PureComponent
<
PropsType
>
{
url
=
''
;
/**
* Open bitcoin link
*/
openLink
=
()
=>
{
Linking
.
openURL
(
this
.
url
);
}
cancel
=
()
=>
{
if
(
this
.
props
.
onCancel
)
{
this
.
props
.
onCancel
();
}
}
/**
* Render
*/
render
():
React
.
Node
{
this
.
url
=
`bitcoin:
${
this
.
props
.
address
}
?amount=
${
this
.
props
.
amount
}
`
;
return
(
<
View
style
=
{[
CS
.
flexContainer
,
CS
.
marginTop3x
]}
>
<
Text
style
=
{[
CS
.
fontXL
,
CS
.
textCenter
]}
>
Tap
to
send
<
Text
style
=
{
CS
.
colorPrimary
}
>
{
this
.
props
.
amount
}
BTC
<
/Text> to</
Text
>
<
Text
style
=
{[
CS
.
colorPrimary
,
CS
.
fontL
]}
numberOfLines
=
{
1
}
>
{
this
.
props
.
address
}
<
/Text
>
<
View
style
=
{
CS
.
rowJustifyCenter
}
>
<
Button
text
=
{
i18nService
.
t
(
'
goback
'
)}
onPress
=
{
this
.
cancel
}
containerStyle
=
{
CS
.
padding
}
textStyle
=
{
CS
.
fontL
}
/
>
<
Button
inverted
text
=
{
i18nService
.
t
(
'
send
'
).
toUpperCase
()}
onPress
=
{
this
.
openLink
}
containerStyle
=
{
CS
.
padding
}
textStyle
=
{
CS
.
fontL
}
/
>
<
/View
>
<
Text
style
=
{[
CS
.
fontXL
,
CS
.
textCenter
,
CS
.
marginTop4x
]}
>
Or
scan
the
following
QR
code
<
/Text
>
<
View
style
=
{[
CS
.
centered
,
CS
.
marginTop3x
]}
>
<
QRCode
value
=
{
this
.
url
}
size
=
{
viewportPercentage
(
70
).
value
}
/
>
<
/View
>
<
/View
>
);
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/wire/methods/PaymentMethodIcon.js
0 → 100644
View file @
f8095bdf
// @flow
import
*
as
React
from
'
react
'
import
Icon
from
'
react-native-vector-icons/FontAwesome5
'
;
type
PropsType
=
{
value
:
string
};
/**
* Payment method selector
*/
export
default
class
PaymentMethodIcon
extends
React
.
PureComponent
<
PropsType
>
{
render
():
React
.
Node
{
const
{
value
,
...
other
}
=
this
.
props
;
let
icon
:
string
=
''
;
switch
(
value
.
toLowerCase
())
{
case
'
tokens
'
:
icon
=
'
lightbulb
'
;
break
;
case
'
usd
'
:
icon
=
'
dollar-sign
'
;
break
;
case
'
btc
'
:
icon
=
'
bitcoin
'
;
break
;
case
'
eth
'
:
icon
=
'
ethereum
'
;
break
;
}
return
<
Icon
name
=
{
icon
}
{...
other
}
/
>
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/wire/methods/PaymentMethodSelector.js
0 → 100644
View file @
f8095bdf
// @flow
import
*
as
React
from
'
react
'
import
{
Text
,
StyleSheet
}
from
'
react-native
'
;
import
Menu
,
{
MenuItem
}
from
'
react-native-material-menu
'
;
import
featuresService
from
'
../../common/services/features.service
'
;
import
testID
from
'
../../common/helpers/testID
'
;
import
Colors
from
'
../../styles/Colors
'
;
import
PaymentMethodIcon
from
'
./PaymentMethodIcon
'
;
import
{
CommonStyle
as
CS
}
from
'
../../styles/Common
'
;
type
PropsType
=
{
button
:
React
.
Node
,
value
:
string
,
onSelect
:
Function
};
/**
* Payment method selector
*/
export
default
class
PaymentMethodSelector
extends
React
.
PureComponent
<
PropsType
>
{
methods
:
Array
<
any
>
;
menuRef
:
?
React
.
ElementRef
<
Menu
>
;
/**
* @param {PropsType} props
*/
constructor
(
props
:
PropsType
)
{
super
(
props
);
if
(
featuresService
.
has
(
'
wire-multi-currency
'
))
{
this
.
methods
=
[
{
label
:
'
Tokens
'
,
handle
:
():
any
=>
this
.
onSelect
(
'
tokens
'
)},
{
label
:
'
USD
'
,
handle
:
():
any
=>
this
.
onSelect
(
'
usd
'
)},
{
label
:
'
BTC
'
,
handle
:
():
any
=>
this
.
onSelect
(
'
btc
'
)},
{
label
:
'
ETH
'
,
handle
:
():
any
=>
this
.
onSelect
(
'
eth
'
)},
];
}
else
{
this
.
methods
=
[{
label
:
'
Tokens
'
,
handle
:
():
any
=>
this
.
onSelect
(
'
tokens
'
)}];
}
this
.
menuRef
=
React
.
createRef
();
}
/**
* On method selected
* @param {*} method
*/
onSelect
(
method
:
any
)
{
if
(
this
.
props
.
onSelect
)
{
this
.
props
.
onSelect
(
method
);
}
if
(
this
.
menuRef
&&
this
.
menuRef
.
current
)
{
this
.
menuRef
.
current
.
hide
();
}
}
/**
* Show menu
*/
show
()
{
if
(
this
.
menuRef
&&
this
.
menuRef
.
current
)
{
this
.
menuRef
.
current
.
show
();
}
}
/**
* Render
*/
render
():
React
.
Node
{
return
(
<
Menu
ref
=
{
this
.
menuRef
}
button
=
{
this
.
props
.
button
}
>
{
this
.
methods
.
map
((
method
:
any
,
i
:
number
):
MenuItem
=>
(
<
MenuItem
key
=
{
i
}
onPress
=
{
method
.
handle
}
textStyle
=
{
CS
.
fontXL
}
{...
testID
(
`PAYMENT METHOD
${
method
.
label
}
`
)}
>
<
Text
style
=
{(
method
.
label
.
toLowerCase
()
===
this
.
props
.
value
)
?
styles
.
selected
:
null
}
><
PaymentMethodIcon
value
=
{
method
.
label
}
size
=
{
15
}
/> {method.label}</
Text
>
<
/MenuItem
>
))}
<
/Menu
>
);
}
}
const
styles
:
any
=
StyleSheet
.
create
({
selected
:
{
color
:
Colors
.
primary
}
})
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/wire/tiers/SubscriptionTierCarousel.js
View file @
f8095bdf
import
React
,
{
PureComponent
,
Fragment
}
from
'
react
'
;
import
{
Text
,
Dimensions
,
View
,
StyleSheet
}
from
'
react-native
'
;
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Text
,
View
}
from
'
react-native
'
;
import
Carousel
from
'
react-native-snap-carousel
'
;
import
featuresService
from
'
../../common/services/features.service
'
;
import
i18n
from
'
../../common/services/i18n.service
'
;
import
ModalPicker
from
'
../../common/components/ModalPicker
'
;
import
RewardsStateDecreaseView
from
'
../../notifications/notification/view/RewardsStateDecreaseView
'
;
import
{
CommonStyle
as
CS
}
from
'
../../styles/Common
'
;
import
viewportPercentage
from
'
../../common/helpers/viewportPercentage
'
;
...
...
@@ -32,6 +29,10 @@ export default class SubscriptionTierCarousel extends PureComponent {
return
amount
>
1
?
'
Tokens
'
:
'
Token
'
;
case
'
usd
'
:
return
'
USD
'
;
case
'
eth
'
:
return
'
ETH
'
;
case
'
btc
'
:
return
'
BTC
'
;
}
}
...
...
@@ -82,7 +83,7 @@ export default class SubscriptionTierCarousel extends PureComponent {
const
amount
=
row
.
item
.
amount
||
this
.
props
.
amount
;
const
currency
=
row
.
item
.
currency
||
this
.
props
.
currency
;
return
(
<
View
key
=
{
`rewards
${
row
.
item
.
amount
}
`
}
style
=
{[
CS
.
rowJustifyCenter
,
CS
.
backgroundLightGreyed
,
CS
.
borderRadius5x
,
CS
.
shadow
,
CS
.
padding2x
,
CS
.
border
,
CS
.
borderGreyed
]}
>
<
View
key
=
{
`rewards
${
row
.
item
.
amount
}
`
}
style
=
{[
CS
.
rowJustifyCenter
,
CS
.
backgroundLightGreyed
,
CS
.
borderRadius5x
,
CS
.
padding2x
,
CS
.
border
,
CS
.
borderGreyed
]}
>
<
View
style
=
{
CS
.
columnAlignCenter
}
>
<
Text
style
=
{[
CS
.
fontXXL
,
CS
.
fontMedium
,
CS
.
colorDark
]}
>
{
amount
}
{
this
.
getPluralizedCurrency
(
currency
,
row
.
item
.
amount
)}
/ month</
Text
>
<
Text
numberOfLines
=
{
5
}
style
=
{[
CS
.
fontL
,
CS
.
fontHairline
,
CS
.
colorDark
]}
>
{
row
.
item
.
description
}
<
/Text
>
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment