- Dapp Front Boilerplate UI-Kit
+ OpenIICO UI-Kit
-
-
-
- EMAIL
-
+
+ [Identicon]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
-exports[`Storyshots Text Input error 1`] = `
+exports[`Storyshots Nav Bar with a lot of routes, (scrollable) 1`] = `
- Dapp Front Boilerplate UI-Kit
+ OpenIICO UI-Kit
-
-
- EMAIL
-
- Please enter a valid email.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
-exports[`Storyshots Text Input touched 1`] = `
+exports[`Storyshots Nav Bar with routes 1`] = `
- Dapp Front Boilerplate UI-Kit
+ OpenIICO UI-Kit
-
- EMAIL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
-exports[`Storyshots Text Input valid 1`] = `
+exports[`Storyshots Page Not Found default 1`] = `
- Dapp Front Boilerplate UI-Kit
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Pie Chart activated 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Requires MetaMask needs unlock 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+ This is a decentralized application. In order to use this site please
+
+
+ unlock
+
+ MetaMask
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Requires MetaMask not found 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+ This is a decentralized application. In order to use this site please
+
+
+ download
+
+ MetaMask
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Slider default 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+ Jan 1st, 2018
+
+
+ Today
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Stat Block default 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ Label
+ :
+
+
+ 300
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Stat Block with no label 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Stat Row default 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+ Label 1
+ :
+
+
+ 300
+
+
+
+
+ Label 2
+ :
+
+
+ 300
+
+
+
+
+ Label 3
+ :
+
+
+ 300
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Stat Row with box shadow 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+ Label 1
+ :
+
+
+ 300
+
+
+
+
+ Label 2
+ :
+
+
+ 300
+
+
+
+
+ Label 3
+ :
+
+
+ 300
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Text Input default 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Text Input error 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Text Input touched 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Text Input valid 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast confirm 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast error 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast info 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast message 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast success 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Toast warning 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ TOAST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Typography headings 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ Heading 1
+
+
+ Heading 2
+
+
+ Heading 3
+
+
+ Heading 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Typography paragraphs 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque sapien nunc, eleifend et sem nec, iaculis tincidunt felis.
+
+
+ Duis sed eros ut lacus maximus sodales id ut nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus accumsan convallis laoreet.
+
+
+ Duis et mauris vestibulum, auctor lacus porttitor, pellentesque arcu. Sed scelerisque dolor in orci luctus semper. Mauris turpis magna, congue vitae sollicitudin vel, pretium nec arcu.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots Typography small 1`] = `
+
+
+
+
+ OpenIICO UI-Kit
+
+
+
+
+
+
+
+ small
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/src/components/button/button.scss b/src/components/button/button.scss
index 1e63a01..5acdbf3 100755
--- a/src/components/button/button.scss
+++ b/src/components/button/button.scss
@@ -3,17 +3,13 @@
/* @define Button */
.Button {
// stylelint-disable-next-line declaration-colon-newline-after
- background: linear-gradient(
- 0deg,
- $buttonGradientStart 0%,
- $buttonGradientEnd 100%
- );
- border-radius: 4px;
- box-shadow: 0 1px 0 0 $buttonBoxShadow;
+ background: $primary;
+ border-radius: 5px;
+ box-shadow: 0 2px 0 0 $primary;
cursor: pointer;
- height: 50px;
+ height: 60px;
min-width: 200px;
- padding: 0 20px;
+ padding: 0 18px;
text-align: center;
&.is-disabled {
@@ -23,8 +19,8 @@
}
&-label {
- color: $buttonText;
- line-height: 50px;
- margin: 0;
+ color: $light;
+ font-size: 20px;
+ line-height: 60px;
}
}
diff --git a/src/components/button/index.js b/src/components/button/index.js
index fc4ed04..50aa027 100755
--- a/src/components/button/index.js
+++ b/src/components/button/index.js
@@ -12,11 +12,11 @@ const Button = ({
...rest
}) => (
-
{children}
+ {children}
)
diff --git a/src/components/chain-hash/index.js b/src/components/chain-hash/index.js
new file mode 100644
index 0000000..7acb6d8
--- /dev/null
+++ b/src/components/chain-hash/index.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+const ChainHash = ({ children }) => (
+
+
+ {children.slice(0, 6) + '...' + children.slice(children.length - 4)}
+
+
+)
+
+ChainHash.propTypes = {
+ // State
+ children: PropTypes.string.isRequired
+}
+
+export default ChainHash
diff --git a/src/components/chain-number/chain-number.scss b/src/components/chain-number/chain-number.scss
new file mode 100644
index 0000000..18b6ad8
--- /dev/null
+++ b/src/components/chain-number/chain-number.scss
@@ -0,0 +1,6 @@
+@import '../../styles/_colors.scss';
+
+/* @define ChainNumber */
+.ChainNumber {
+ color: $info;
+}
diff --git a/src/components/chain-number/index.js b/src/components/chain-number/index.js
new file mode 100644
index 0000000..538cc2d
--- /dev/null
+++ b/src/components/chain-number/index.js
@@ -0,0 +1,17 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import './chain-number.css'
+
+const ChainNumber = ({ children }) => (
+
+ {children.toFixed(2)}
+
+)
+
+ChainNumber.propTypes = {
+ // State
+ children: PropTypes.number.isRequired
+}
+
+export default ChainNumber
diff --git a/src/components/circle/circle.scss b/src/components/circle/circle.scss
new file mode 100644
index 0000000..a96a669
--- /dev/null
+++ b/src/components/circle/circle.scss
@@ -0,0 +1,4 @@
+/* @define Circle */
+.Circle {
+ border-radius: 50%;
+}
diff --git a/src/components/circle/index.js b/src/components/circle/index.js
new file mode 100644
index 0000000..15a9bae
--- /dev/null
+++ b/src/components/circle/index.js
@@ -0,0 +1,19 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import './circle.css'
+
+const Circle = ({ size, color }) => (
+
+)
+
+Circle.propTypes = {
+ // State
+ size: PropTypes.number.isRequired,
+ color: PropTypes.string.isRequired
+}
+
+export default Circle
diff --git a/src/components/form-header/form-header.scss b/src/components/form-header/form-header.scss
new file mode 100644
index 0000000..9280265
--- /dev/null
+++ b/src/components/form-header/form-header.scss
@@ -0,0 +1,9 @@
+@import '../../styles/_colors.scss';
+
+/* @define FormHeader */
+.FormHeader {
+ border-bottom: 1px solid $dark3;
+ margin: 0 -30px 29px;
+ padding: 28px 30px;
+ width: calc(100% + 60px);
+}
diff --git a/src/components/form-header/index.js b/src/components/form-header/index.js
new file mode 100644
index 0000000..203d2ca
--- /dev/null
+++ b/src/components/form-header/index.js
@@ -0,0 +1,17 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import './form-header.css'
+
+const FormHeader = ({ title }) => (
+
+
{title}
+
+)
+
+FormHeader.propTypes = {
+ // State
+ title: PropTypes.string.isRequired
+}
+
+export default FormHeader
diff --git a/src/components/nav-bar/index.js b/src/components/nav-bar/index.js
new file mode 100644
index 0000000..3b6b0bd
--- /dev/null
+++ b/src/components/nav-bar/index.js
@@ -0,0 +1,65 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { NavLink } from 'react-router-dom'
+import { RenderIf } from 'lessdux'
+
+import * as walletSelectors from '../../reducers/wallet'
+import Identicon from '../../components/identicon'
+import logo from '../../assets/images/logo.png'
+
+import './nav-bar.css'
+
+const NavBar = ({ accounts, balance, routes }) => (
+
+
+
+
+
+ {routes.map(r => (
+
+ {r.name}
+
+ ))}
+
+
+
+ }
+ failedLoading="..."
+ />
+
+
+
+
+
+
+)
+
+NavBar.propTypes = {
+ // Redux State
+ accounts: walletSelectors.accountsShape.isRequired,
+ balance: walletSelectors.balanceShape.isRequired,
+
+ // State
+ routes: PropTypes.arrayOf(
+ PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ to: PropTypes.string.isRequired
+ }).isRequired
+ ).isRequired
+}
+
+export default NavBar
diff --git a/src/components/nav-bar/nav-bar.scss b/src/components/nav-bar/nav-bar.scss
new file mode 100644
index 0000000..81a7fa2
--- /dev/null
+++ b/src/components/nav-bar/nav-bar.scss
@@ -0,0 +1,57 @@
+@import '../../styles/_colors.scss';
+
+/* @define NavBar */
+.NavBar {
+ align-items: center;
+ background: $light2;
+ border-bottom: 1px solid transparentize($dark4, 0.8);
+ display: flex;
+ height: 70px;
+ padding: 0 8%;
+ position: absolute;
+ top: 0;
+ width: 100%;
+
+ &-logo {
+ height: 40px;
+ width: 40px;
+ }
+
+ &-tabs {
+ align-items: center;
+ display: flex;
+ height: 100%;
+ margin: 0 50px 0 25px;
+ overflow-x: scroll;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ &-tab {
+ color: $dark;
+ font-size: 15px;
+ font-weight: 300;
+ padding: 0 25px;
+
+ &:hover,
+ &.is-active {
+ color: $dark3;
+ }
+ }
+ }
+
+ &-buttons {
+ align-items: center;
+ color: $dark;
+ display: flex;
+ margin-left: auto;
+
+ &-button {
+ border-radius: 18px;
+ cursor: pointer;
+ height: 36px;
+ margin-right: 20px;
+ overflow: hidden;
+ width: 36px;
+ }
+ }
+}
diff --git a/src/components/pie-chart/index.js b/src/components/pie-chart/index.js
new file mode 100644
index 0000000..454cf3d
--- /dev/null
+++ b/src/components/pie-chart/index.js
@@ -0,0 +1,35 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import ReactMinimalPieChart from 'react-minimal-pie-chart'
+
+import './pie-chart.css'
+
+const PieChart = ({ slice, total, size }) => (
+
+)
+
+PieChart.propTypes = {
+ // State
+ slice: PropTypes.number.isRequired,
+ total: PropTypes.number.isRequired,
+ size: PropTypes.number.isRequired
+}
+
+export default PieChart
diff --git a/src/components/pie-chart/pie-chart.scss b/src/components/pie-chart/pie-chart.scss
new file mode 100644
index 0000000..ff31000
--- /dev/null
+++ b/src/components/pie-chart/pie-chart.scss
@@ -0,0 +1,4 @@
+/* @define PieChart */
+.PieChart {
+ margin: auto;
+}
diff --git a/src/components/requires-meta-mask/index.js b/src/components/requires-meta-mask/index.js
index 1d18c05..8d3d4db 100755
--- a/src/components/requires-meta-mask/index.js
+++ b/src/components/requires-meta-mask/index.js
@@ -21,10 +21,12 @@ const RequiresMetaMask = ({ needsUnlock }) => (
)
RequiresMetaMask.propTypes = {
+ // State
needsUnlock: PropTypes.bool
}
RequiresMetaMask.defaultProps = {
+ // State
needsUnlock: false
}
diff --git a/src/components/slider/index.js b/src/components/slider/index.js
new file mode 100644
index 0000000..ebbd9cf
--- /dev/null
+++ b/src/components/slider/index.js
@@ -0,0 +1,74 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+import './slider.css'
+
+class Slider extends PureComponent {
+ static propTypes = {
+ // State
+ startLabel: PropTypes.string.isRequired,
+ endLabel: PropTypes.string.isRequired,
+ initialPercent: PropTypes.number.isRequired,
+
+ // Handlers
+ calcValue: PropTypes.func.isRequired
+ }
+
+ state = {
+ left: 0,
+ value: null
+ }
+
+ barRef = null
+
+ getBarRef = ref => {
+ const { initialPercent, calcValue } = this.props
+
+ this.barRef = ref
+
+ /* istanbul ignore if */
+ if (this.barRef && process.env.NODE_ENV !== 'test')
+ this.setState({
+ left: this.barRef.getBoundingClientRect().width * initialPercent,
+ value: calcValue(initialPercent)
+ })
+ }
+
+ handleBarMouseMove = event => {
+ const { calcValue } = this.props
+
+ const boundingClientRect = this.barRef.getBoundingClientRect()
+ const left = event.pageX - boundingClientRect.left
+ const percent = left / boundingClientRect.width
+ this.setState({
+ left,
+ value: calcValue(percent)
+ })
+ }
+
+ render() {
+ const { startLabel, endLabel } = this.props
+ const { left, value } = this.state
+ return (
+
+
+
+ {value && (
+
+
{value}
+
+ )}
+
+
{startLabel}
+
{endLabel}
+
+
+ )
+ }
+}
+
+export default Slider
diff --git a/src/components/slider/slider.scss b/src/components/slider/slider.scss
new file mode 100644
index 0000000..6e32e57
--- /dev/null
+++ b/src/components/slider/slider.scss
@@ -0,0 +1,35 @@
+@import '../../styles/_colors.scss';
+
+/* @define Slider */
+.Slider {
+ padding-top: 5px;
+ position: relative;
+
+ &-bar {
+ background: $light2;
+ height: 15px;
+ }
+
+ &-thumb {
+ background: $primary;
+ height: 25px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ transform: translateX(-50%);
+ width: 5px;
+ }
+
+ &-value {
+ left: 0;
+ padding: 5px;
+ position: absolute;
+ top: -27px;
+ transform: translateX(-50%);
+ }
+
+ &-labels {
+ display: flex;
+ justify-content: space-between;
+ }
+}
diff --git a/src/components/stat-block/index.js b/src/components/stat-block/index.js
new file mode 100644
index 0000000..142f00e
--- /dev/null
+++ b/src/components/stat-block/index.js
@@ -0,0 +1,45 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import './stat-block.css'
+
+const StatBlock = ({ label, value, noBackground, noFlex, flexBasis }) => (
+
+ {label &&
{label}: }
+
+ {value}
+
+
+)
+
+StatBlock.propTypes = {
+ // State
+ label: PropTypes.string,
+ value: PropTypes.node.isRequired,
+
+ // Modifiers
+ noBackground: PropTypes.bool,
+ noFlex: PropTypes.bool,
+ flexBasis: PropTypes.number
+}
+
+StatBlock.defaultProps = {
+ // State
+ label: null,
+
+ // Modifiers
+ noBackground: false,
+ noFlex: false,
+ flexBasis: null
+}
+
+export default StatBlock
diff --git a/src/components/stat-block/stat-block.scss b/src/components/stat-block/stat-block.scss
new file mode 100644
index 0000000..f9adb03
--- /dev/null
+++ b/src/components/stat-block/stat-block.scss
@@ -0,0 +1,26 @@
+@import '../../styles/_colors.scss';
+
+/* @define StatBlock */
+.StatBlock {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ justify-content: flex-end;
+ margin: 10px;
+
+ &--withNoLabel {
+ background: $light2;
+ border-radius: 5px;
+ padding: 21px 47px;
+ }
+
+ &--noFlex {
+ flex: initial;
+ }
+
+ &-value {
+ &--withNoLabel {
+ margin: 0;
+ }
+ }
+}
diff --git a/src/components/stat-row/index.js b/src/components/stat-row/index.js
new file mode 100644
index 0000000..ebaa921
--- /dev/null
+++ b/src/components/stat-row/index.js
@@ -0,0 +1,25 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import './stat-row.css'
+
+const StatRow = ({ children, withBoxShadow }) => (
+
+)
+
+StatRow.propTypes = {
+ // State
+ children: PropTypes.arrayOf(PropTypes.node.isRequired).isRequired,
+
+ // Modifiers
+ withBoxShadow: PropTypes.bool
+}
+
+StatRow.defaultProps = {
+ // Modifiers
+ withBoxShadow: false
+}
+
+export default StatRow
diff --git a/src/components/stat-row/stat-row.scss b/src/components/stat-row/stat-row.scss
new file mode 100644
index 0000000..5ba536d
--- /dev/null
+++ b/src/components/stat-row/stat-row.scss
@@ -0,0 +1,26 @@
+@import '../../styles/_colors.scss';
+
+/* @define StatRow */
+.StatRow {
+ border-bottom: 2px solid $light3;
+ padding: 25.5px 0 0 0;
+ width: 100%;
+
+ &--withBoxShadow {
+ background: $light;
+ border: none;
+ /* stylelint-disable declaration-colon-newline-after, value-list-comma-newline-after */
+ box-shadow: 0 0 6px 0 rgba(71, 82, 93, 0.09),
+ 0 0 1px 0 rgba(77, 78, 90, 0.08), 0 1px 0 0 rgba(71, 82, 93, 0.09);
+ /* stylelint-enable */
+ padding: 25.5px 41.5px;
+ }
+
+ &-blocks {
+ align-items: center;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ margin: -10px;
+ }
+}
diff --git a/src/components/text-input/index.js b/src/components/text-input/index.js
index de2ff4d..f380530 100755
--- a/src/components/text-input/index.js
+++ b/src/components/text-input/index.js
@@ -4,32 +4,36 @@ import PropTypes from 'prop-types'
import './text-input.css'
const TextInput = ({
- input: { value, onChange },
+ input: { value, onBlur, onChange },
meta: { touched, valid, error },
placeholder,
+ type,
className
}) => (
{placeholder && (
{placeholder}
)}
- {error &&
{error}
}
+ {touched && error &&
{error}
}
)
@@ -37,6 +41,7 @@ TextInput.propTypes = {
// Redux Form
input: PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ onBlur: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired
}).isRequired,
meta: PropTypes.shape({
@@ -50,6 +55,7 @@ TextInput.propTypes = {
.isRequired,
// Modifiers
+ type: PropTypes.string,
className: PropTypes.string
}
@@ -58,6 +64,7 @@ TextInput.defaultProps = {
meta: {},
// Modifiers
+ type: 'text',
className: ''
}
diff --git a/src/components/text-input/text-input.scss b/src/components/text-input/text-input.scss
index 3d2d084..25f9d7f 100755
--- a/src/components/text-input/text-input.scss
+++ b/src/components/text-input/text-input.scss
@@ -42,16 +42,17 @@
&.is-touched {
font-size: 8px;
line-height: 8px;
- top: 5px;
+ top: 2px;
transform: none;
}
}
&-error {
- bottom: 0;
+ bottom: -11.5px;
color: $error;
font-size: 8px;
left: 5px;
+ pointer-events: none;
position: absolute;
}
}
diff --git a/src/constants/date.js b/src/constants/date.js
new file mode 100644
index 0000000..4d33d68
--- /dev/null
+++ b/src/constants/date.js
@@ -0,0 +1,27 @@
+export const MONTHS_ENUM = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December'
+]
+
+export const ORDINAL_INDICATOR_ENUM = [
+ 'th',
+ 'st',
+ 'nd',
+ 'rd',
+ 'th',
+ 'th',
+ 'th',
+ 'th',
+ 'th',
+ 'th'
+]
diff --git a/src/containers/balance/balance.scss b/src/containers/balance/balance.scss
deleted file mode 100755
index dd59123..0000000
--- a/src/containers/balance/balance.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-/* @define Balance */
-.Balance {
- background: #273142;
- height: 100%;
-
- &-message {
- color: white;
- font-size: 40px;
- padding-top: 10%;
- text-align: center;
-
- &-link {
- color: #999;
- text-decoration: none;
- }
- }
-}
diff --git a/src/containers/balance/balance.test.js b/src/containers/balance/balance.test.js
deleted file mode 100755
index 5f6b338..0000000
--- a/src/containers/balance/balance.test.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import setupIntegrationTest, {
- flushPromises
-} from '../../bootstrap/setup-integration-test'
-
-import Balance from '.'
-
-let integration = {
- store: null,
- history: null,
- dispatchSpy: null,
- mountApp: null
-}
-
-beforeEach(() => {
- integration = setupIntegrationTest({ router: { location: '/' } })
-})
-
-it('Renders and loads balance correctly.', async () => {
- const app = integration.mountApp()
- await flushPromises()
- app.update()
- expect(app.find(Balance).text()).toBe(
- 'Hello CryptoWorldWelcome [Identicon], You have 100 ETH.'
- )
-})
diff --git a/src/containers/balance/index.js b/src/containers/balance/index.js
deleted file mode 100755
index aafbfb0..0000000
--- a/src/containers/balance/index.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, { PureComponent } from 'react'
-import PropTypes from 'prop-types'
-import { connect } from 'react-redux'
-import { RenderIf } from 'lessdux'
-
-import * as walletActions from '../../actions/wallet'
-import * as walletSelectors from '../../reducers/wallet'
-import Identicon from '../../components/identicon'
-
-import './balance.css'
-
-class Balance extends PureComponent {
- static propTypes = {
- balance: walletSelectors.balanceShape.isRequired,
- fetchBalance: PropTypes.func.isRequired
- }
-
- componentDidMount() {
- const { fetchBalance } = this.props
- fetchBalance()
- }
-
- render() {
- const { balance } = this.props
-
- return (
-
-
- Hello CryptoWorld
-
-
-
-
-
- Welcome , You have{' '}
- {balance.data.toString()} ETH.
-
- )
- }
- failedLoading={
-
- There was an error fetching your balance. Make sure{' '}
-
- MetaMask
- {' '}
- is unlocked and refresh the page.
-
- }
- />
-
-
- )
- }
-}
-
-export default connect(
- state => ({
- balance: state.wallet.balance
- }),
- {
- fetchBalance: walletActions.fetchBalance
- }
-)(Balance)
diff --git a/src/containers/home/components/iico-address-form/index.js b/src/containers/home/components/iico-address-form/index.js
new file mode 100644
index 0000000..529eb29
--- /dev/null
+++ b/src/containers/home/components/iico-address-form/index.js
@@ -0,0 +1,17 @@
+import { form } from '../../../../utils/form-generator'
+import { required } from '../../../../utils/validation'
+
+export const {
+ Form: IICOAddressForm,
+ isInvalid: getIICOAddressFormIsInvalid,
+ submit: submitIICOAddressForm
+} = form('IICOAddressForm', {
+ header: {
+ type: 'header',
+ props: { title: 'Enter the address of the IICO and hit enter.' }
+ },
+ address: {
+ type: 'text',
+ validate: [required]
+ }
+})
diff --git a/src/containers/home/home.scss b/src/containers/home/home.scss
new file mode 100755
index 0000000..624a221
--- /dev/null
+++ b/src/containers/home/home.scss
@@ -0,0 +1,16 @@
+@import '../../styles/_colors.scss';
+
+/* @define Home */
+.Home {
+ height: 100%;
+ padding: 10px 20px;
+
+ &-result {
+ margin-top: 20px;
+ padding-left: 40px;
+
+ &-link {
+ margin: 5px;
+ }
+ }
+}
diff --git a/src/containers/home/index.js b/src/containers/home/index.js
new file mode 100755
index 0000000..698d5a3
--- /dev/null
+++ b/src/containers/home/index.js
@@ -0,0 +1,91 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { Link } from 'react-router-dom'
+import { RenderIf } from 'lessdux'
+
+import * as IICOSelectors from '../../reducers/iico'
+import * as IICOActions from '../../actions/iico'
+import Identicon from '../../components/identicon'
+
+import {
+ IICOAddressForm,
+ submitIICOAddressForm
+} from './components/iico-address-form'
+
+import './home.css'
+
+class Home extends PureComponent {
+ static propTypes = {
+ // Redux State
+ IICOData: IICOSelectors.IICODataShape.isRequired,
+
+ // Action Dispatchers
+ clearIICOData: PropTypes.func.isRequired,
+ fetchIICOData: PropTypes.func.isRequired,
+
+ // IICOAddressForm
+ submitIICOAddressForm: PropTypes.func.isRequired
+ }
+
+ componentDidMount() {
+ const { clearIICOData } = this.props
+ clearIICOData()
+ }
+
+ handleIICOAddressFormSubmit = formData => {
+ const { fetchIICOData } = this.props
+ fetchIICOData(formData.address)
+ }
+
+ handleKeyPress = event => {
+ if (event.key === 'Enter') {
+ event.preventDefault()
+ const { submitIICOAddressForm } = this.props
+ submitIICOAddressForm()
+ }
+ }
+
+ render() {
+ const { IICOData } = this.props
+
+ return (
+
+
+
+
+
+
+
+ Go To IICO Page
+
+
+
+ )
+ }
+ failedLoading={
+ IICOData.data !== null &&
+ 'The address or the contract it holds is invalid. Try another one.'
+ }
+ />
+
+
+ )
+ }
+}
+
+export default connect(
+ state => ({
+ IICOData: state.IICO.IICOData
+ }),
+ {
+ clearIICOData: IICOActions.clearIICOData,
+ fetchIICOData: IICOActions.fetchIICOData,
+ submitIICOAddressForm
+ }
+)(Home)
diff --git a/src/containers/iico/components/bids/bids.scss b/src/containers/iico/components/bids/bids.scss
new file mode 100644
index 0000000..bfbc082
--- /dev/null
+++ b/src/containers/iico/components/bids/bids.scss
@@ -0,0 +1,16 @@
+/* @define Bids */
+.Bids {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 55px;
+ width: 100%;
+
+ &-form-fieldset-fields {
+ justify-content: space-around;
+ }
+
+ &-confirmWithdrawal {
+ padding: 15px;
+ text-align: center;
+ }
+}
diff --git a/src/containers/iico/components/bids/index.js b/src/containers/iico/components/bids/index.js
new file mode 100644
index 0000000..cda1bda
--- /dev/null
+++ b/src/containers/iico/components/bids/index.js
@@ -0,0 +1,275 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { toastr } from 'react-redux-toastr'
+import { SyncLoader } from 'react-spinners'
+
+import * as IICOSelectors from '../../../../reducers/iico'
+import * as IICOActions from '../../../../actions/iico'
+import {
+ SubmitBidForm,
+ getSubmitBidFormIsInvalid,
+ submitSubmitBidForm
+} from '../submit-bid-form'
+import {
+ FinalizeIICOForm,
+ getFinalizeIICOFormIsInvalid,
+ submitFinalizeIICOForm
+} from '../finalize-iico-form'
+import ChainNumber from '../../../../components/chain-number'
+import StatRow from '../../../../components/stat-row'
+import StatBlock from '../../../../components/stat-block'
+import Button from '../../../../components/button'
+import { numberToPercentage } from '../../../../utils/number'
+
+import './bids.css'
+
+class Bids extends PureComponent {
+ static propTypes = {
+ // Redux State
+ IICOBid: IICOSelectors.IICOBidShape.isRequired,
+
+ // Action Dispatchers
+ createIICOBid: PropTypes.func.isRequired,
+ withdrawIICOBid: PropTypes.func.isRequired,
+ finalizeIICO: PropTypes.func.isRequired,
+ redeemIICOBid: PropTypes.func.isRequired,
+
+ // submitBidForm
+ submitBidFormIsInvalid: PropTypes.bool.isRequired,
+ submitSubmitBidForm: PropTypes.func.isRequired,
+
+ // finalizeIICOForm
+ finalizeIICOFormIsInvalid: PropTypes.bool.isRequired,
+ submitFinalizeIICOForm: PropTypes.func.isRequired,
+
+ // State
+ address: PropTypes.string.isRequired,
+ data: IICOSelectors._IICODataShape.isRequired,
+ bids: IICOSelectors._IICOBidsShape.isRequired
+ }
+
+ handleSubmitBidFormSubmit = formData => {
+ const { address, createIICOBid } = this.props
+ createIICOBid(address, formData.amount, formData.personalCap)
+ }
+
+ handleWithdrawClick = ({ currentTarget: { id } }) => {
+ const { address, data, bids, withdrawIICOBid } = this.props
+
+ const now = Date.now()
+ const endFullBonusTime = data.endFullBonusTime.getTime()
+ const withdrawalLockTime = data.withdrawalLockTime.getTime()
+ const bid = bids[id]
+
+ const lockedIn =
+ now < endFullBonusTime
+ ? 0
+ : bid.contrib *
+ (1 -
+ (withdrawalLockTime - now) /
+ (withdrawalLockTime - endFullBonusTime))
+ const newBonus = bid.bonus - bid.bonus / 3
+
+ toastr.confirm(null, {
+ okText: 'Yes',
+ onOk: () => withdrawIICOBid(address, Number(id)),
+ component: () => (
+