Jack Mallers
7 years ago
12 changed files with 696 additions and 12 deletions
@ -0,0 +1,154 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import Isvg from 'react-inlinesvg' |
|||
import { FaCircle, FaQuestionCircle } from 'react-icons/lib/fa' |
|||
|
|||
import x from 'icons/x.svg' |
|||
|
|||
import styles from './AddChannel.scss' |
|||
|
|||
const AddChannel = ({ |
|||
contactsform, |
|||
contactsform: { showErrors }, |
|||
closeContactsForm, |
|||
openSubmitChannelForm, |
|||
updateContactFormSearchQuery, |
|||
updateManualFormSearchQuery, |
|||
updateContactCapacity, |
|||
setPubkey, |
|||
openChannel, |
|||
updateManualFormErrors, |
|||
activeChannelPubkeys, |
|||
nonActiveChannelPubkeys, |
|||
pendingOpenChannelPubkeys, |
|||
filteredNetworkNodes, |
|||
loadingChannelPubkeys, |
|||
showManualForm, |
|||
manualFormIsValid |
|||
}) => { |
|||
|
|||
const renderRightSide = (node) => { |
|||
if (loadingChannelPubkeys.includes(node.pub_key)) { |
|||
return ( |
|||
<span className={styles.inactive}> |
|||
<div className={styles.loading}> |
|||
<div className={styles.spinner} /> |
|||
</div> |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
if (activeChannelPubkeys.includes(node.pub_key)) { |
|||
return ( |
|||
<span className={`${styles.online} ${styles.inactive}`}> |
|||
<span>Online</span> |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
if (nonActiveChannelPubkeys.includes(node.pub_key)) { |
|||
return ( |
|||
<span className={`${styles.offline} ${styles.inactive}`}> |
|||
<span>Offline</span> |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
if (pendingOpenChannelPubkeys.includes(node.pub_key)) { |
|||
return ( |
|||
<span className={`${styles.pending} ${styles.inactive}`}> |
|||
<span>Pending</span> |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
if (!node.addresses.length) { |
|||
return ( |
|||
<span className={`${styles.private} ${styles.inactive}`}> |
|||
Private |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
return ( |
|||
<span |
|||
className={styles.connect} |
|||
onClick={() => { |
|||
// set the node public key for the submit form
|
|||
setPubkey(node.pub_key) |
|||
// open the submit form
|
|||
openSubmitChannelForm() |
|||
}} |
|||
> |
|||
Connect |
|||
</span> |
|||
) |
|||
} |
|||
|
|||
const searchUpdated = (search) => { |
|||
updateContactFormSearchQuery(search) |
|||
|
|||
if (search.includes('@') && search.split('@')[0].length === 66) { |
|||
updateManualFormSearchQuery(search) |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<div className={styles.container}> |
|||
<header className={styles.header}> |
|||
<input |
|||
type='text' |
|||
placeholder='Search the network...' |
|||
className={styles.searchInput} |
|||
value={contactsform.searchQuery} |
|||
onChange={event => searchUpdated(event.target.value)} |
|||
ref={input => input && input.focus()} |
|||
/> |
|||
<span onClick={closeContactsForm} className={styles.closeIcon}> |
|||
<Isvg src={x} /> |
|||
</span> |
|||
</header> |
|||
|
|||
<section className={styles.nodes}> |
|||
<ul className={styles.networkResults}> |
|||
{ |
|||
filteredNetworkNodes.map(node => ( |
|||
<li key={node.pub_key}> |
|||
<section> |
|||
{ |
|||
node.alias.length > 0 ? |
|||
<h2> |
|||
<span>{node.alias.trim()}</span> |
|||
<span>({node.pub_key.substr(0, 10)}...{node.pub_key.substr(node.pub_key.length - 10)})</span> |
|||
</h2> |
|||
: |
|||
<h2> |
|||
<span>{node.pub_key}</span> |
|||
</h2> |
|||
} |
|||
</section> |
|||
<section> |
|||
{renderRightSide(node)} |
|||
</section> |
|||
</li> |
|||
)) |
|||
} |
|||
</ul> |
|||
</section> |
|||
|
|||
{ |
|||
showManualForm && |
|||
<section className={styles.manualForm}> |
|||
<p>Hm, looks like we can't see that node from here, wanna try to manually connect?</p> |
|||
<div className={styles.manualConnectButton}>Connect Manually</div> |
|||
</section> |
|||
} |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
AddChannel.propTypes = { |
|||
|
|||
} |
|||
|
|||
export default AddChannel |
@ -0,0 +1,141 @@ |
|||
@import '../../variables.scss'; |
|||
|
|||
.container { |
|||
position: relative; |
|||
width: 30%; |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
height: 100vh; |
|||
background: #31343f; |
|||
} |
|||
|
|||
.header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
background: linear-gradient(270deg, #868B9F 0%, #333C5E 100%); |
|||
padding: 15px 10px; |
|||
color: $white; |
|||
|
|||
input { |
|||
background: transparent; |
|||
outline: 0; |
|||
border: 0; |
|||
color: $white; |
|||
font-size: 14px; |
|||
width: 90%; |
|||
} |
|||
|
|||
.closeIcon { |
|||
cursor: pointer; |
|||
transition: all 0.25s; |
|||
|
|||
&:hover { |
|||
opacity: 0.5; |
|||
} |
|||
|
|||
svg { |
|||
height: 14px; |
|||
width: 14px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.nodes { |
|||
background: #31343F; |
|||
|
|||
.networkResults { |
|||
overflow-y: auto; |
|||
margin-top: 30px; |
|||
padding: 0 10px; |
|||
color: $white; |
|||
|
|||
li { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
padding: 10px 0; |
|||
|
|||
h2 { |
|||
font-size: 10px; |
|||
font-weight: bold; |
|||
letter-spacing: 1.3px; |
|||
|
|||
span { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
|
|||
&:nth-child(1) { |
|||
font-size: 10px; |
|||
font-weight: bold; |
|||
letter-spacing: 1.3px; |
|||
} |
|||
|
|||
&:nth-child(2) { |
|||
display: block; |
|||
color: $darkestgrey; |
|||
font-size: 8px; |
|||
margin-top: 5px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.connect { |
|||
cursor: pointer; |
|||
color: $darkestgrey; |
|||
transition: all 0.25s; |
|||
font-size: 10px; |
|||
|
|||
&:hover { |
|||
color: darken($darkestgrey, 10%); |
|||
} |
|||
} |
|||
|
|||
.inactive { |
|||
font-size: 10px; |
|||
|
|||
display: inline-block; |
|||
vertical-align: top; |
|||
|
|||
&.online { |
|||
color: $green; |
|||
} |
|||
|
|||
&.offline { |
|||
color: $darkestgrey; |
|||
} |
|||
|
|||
&.pending { |
|||
color: $orange; |
|||
} |
|||
|
|||
&.private { |
|||
color: darken($darkestgrey, 50%); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.manualForm { |
|||
color: $white; |
|||
text-align: center; |
|||
margin: 0 25px; |
|||
|
|||
p { |
|||
font-size: 14px; |
|||
margin: 20px 0; |
|||
} |
|||
|
|||
div { |
|||
background: #383B47; |
|||
font-size: 16px; |
|||
padding: 10px; |
|||
cursor: pointer; |
|||
transition: all 0.25s; |
|||
|
|||
&:hover { |
|||
background: lighten(#383B47, 10%); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,89 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
|
|||
import { FaAngleDown } from 'react-icons/lib/fa' |
|||
import Isvg from 'react-inlinesvg' |
|||
import x from 'icons/x.svg' |
|||
|
|||
import styles from './SubmitChannelForm.scss' |
|||
|
|||
class SubmitChannelForm extends React.Component { |
|||
render() { |
|||
const { |
|||
submitChannelFormOpen, |
|||
closeSubmitChannelForm, |
|||
|
|||
pubkey, |
|||
contactCapacity, |
|||
updateContactCapacity, |
|||
|
|||
toggleCurrencyProps: { |
|||
setContactsCurrencyFilters, |
|||
setCurrencyFilters, |
|||
showCurrencyFilters, |
|||
currencyName, |
|||
currentCurrencyFilters, |
|||
onCurrencyFilterClick, |
|||
contactFormUsdAmount |
|||
} |
|||
} = this.props |
|||
|
|||
if (!submitChannelFormOpen) { return null } |
|||
|
|||
return ( |
|||
<div className={styles.container}> |
|||
<div className={styles.closeContainer}> |
|||
<span onClick={closeSubmitChannelForm}> |
|||
<Isvg src={x} /> |
|||
</span> |
|||
</div> |
|||
|
|||
<div className={styles.content}> |
|||
<header className={styles.header}> |
|||
<h1>Add Funds to Network</h1> |
|||
<p>Adding a connection will help you send and receive money on the Lightning Network. You aren't spening any money, rather moving the money you plan to use onto the network.</p> |
|||
</header> |
|||
|
|||
<section className={styles.title}> |
|||
<h2>{pubkey}</h2> |
|||
</section> |
|||
|
|||
<section className={styles.amount}> |
|||
<div className={styles.input}> |
|||
<input |
|||
type='number' |
|||
min='0' |
|||
ref={(input) => { this.amountInput = input }} |
|||
size='' |
|||
placeholder='0.00000000' |
|||
value={contactCapacity || ''} |
|||
onChange={event => updateContactCapacity(event.target.value)} |
|||
// onBlur={onPayAmountBlur}
|
|||
id='amount' |
|||
/> |
|||
<div className={styles.currency}> |
|||
<section className={styles.currentCurrency} onClick={() => setContactsCurrencyFilters(!showCurrencyFilters)}> |
|||
<span>{currencyName}</span><span><FaAngleDown /></span> |
|||
</section> |
|||
<ul className={showCurrencyFilters && styles.active}> |
|||
{ |
|||
currentCurrencyFilters.map(filter => |
|||
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>{filter.name}</li>) |
|||
} |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className={styles.usdAmount}> |
|||
{`≈ ${contactFormUsdAmount || 0} USD`} |
|||
</div> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
} |
|||
|
|||
SubmitChannelForm.propTypes = {} |
|||
|
|||
export default SubmitChannelForm |
@ -0,0 +1,154 @@ |
|||
@import '../../variables.scss'; |
|||
|
|||
.container { |
|||
position: absolute; |
|||
top: 0; |
|||
z-index: 10; |
|||
height: 100vh; |
|||
width: 100%; |
|||
background: #31343F; |
|||
} |
|||
|
|||
.closeContainer { |
|||
text-align: right; |
|||
padding: 20px 40px 0px; |
|||
|
|||
span { |
|||
cursor: pointer; |
|||
opacity: 1.0; |
|||
transition: 0.25s all; |
|||
|
|||
&:hover { |
|||
opacity: 0.5; |
|||
} |
|||
} |
|||
|
|||
svg { |
|||
color: $white; |
|||
} |
|||
} |
|||
|
|||
|
|||
.content { |
|||
padding: 0 40px; |
|||
font-family: Roboto; |
|||
color: $white; |
|||
|
|||
.header { |
|||
padding: 20px 100px; |
|||
|
|||
h1 { |
|||
margin-bottom: 15px; |
|||
font-size: 20px; |
|||
} |
|||
|
|||
p { |
|||
text-align: left; |
|||
line-height: 1.3; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.header { |
|||
text-align: center; |
|||
padding-bottom: 20px; |
|||
border-bottom: 1px solid $spaceborder; |
|||
|
|||
h1 { |
|||
font-size: 22px; |
|||
font-weight: 100; |
|||
margin-top: 10px; |
|||
letter-spacing: 1.5px; |
|||
} |
|||
} |
|||
|
|||
.title { |
|||
margin: 50px 0; |
|||
|
|||
h2 { |
|||
font-size: 14px; |
|||
background: $spaceblue; |
|||
padding: 10px; |
|||
border-radius: 17.5px; |
|||
display: inline; |
|||
} |
|||
} |
|||
|
|||
.input { |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
|
|||
input { |
|||
font-size: 40px; |
|||
max-width: 230px; |
|||
} |
|||
} |
|||
|
|||
.input input { |
|||
background: transparent; |
|||
outline: none; |
|||
border: 0; |
|||
color: $gold; |
|||
-webkit-text-fill-color: $white; |
|||
width: 100%; |
|||
font-weight: 200; |
|||
} |
|||
|
|||
.input input::-webkit-input-placeholder, ::-webkit-input-placeholder { |
|||
text-shadow: none; |
|||
-webkit-text-fill-color: initial; |
|||
} |
|||
|
|||
.currency { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
|
|||
.currentCurrency { |
|||
cursor: pointer; |
|||
transition: 0.25s all; |
|||
|
|||
&:hover { |
|||
opacity: 0.5; |
|||
} |
|||
|
|||
span { |
|||
font-size: 14px; |
|||
|
|||
&:nth-child(1) { |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
ul { |
|||
visibility: hidden; |
|||
position: absolute; |
|||
top: 30px; |
|||
|
|||
&.active { |
|||
visibility: visible; |
|||
} |
|||
|
|||
li { |
|||
padding: 8px 15px; |
|||
background: #191919; |
|||
cursor: pointer; |
|||
transition: 0.25s hover; |
|||
border-bottom: 1px solid #0f0f0f; |
|||
|
|||
&:hover { |
|||
background: #0f0f0f; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.usdAmount { |
|||
margin-top: 20px; |
|||
opacity: 0.5; |
|||
} |
Loading…
Reference in new issue