From 790504fed182e4d43c9bdd4ba06a1b323bd30400 Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munteanu@thinslices.com>
Date: Wed, 10 Jan 2018 15:48:57 +0200
Subject: [PATCH] Add dropdown and steps components

---
 .../component-wizard/components/Dropdown.js   | 67 +++++++++++++++++++
 .../components/Dropdown.local.scss            | 57 ++++++++++++++++
 .../app/component-wizard/components/Steps.js  | 40 +++++++++++
 .../components/Steps.local.scss               | 41 ++++++++++++
 .../app/component-wizard/components/Wizard.js | 47 +++++++------
 .../app/component-wizard/index.js             |  2 +
 6 files changed, 233 insertions(+), 21 deletions(-)
 create mode 100644 packages/xpub-faraday/app/component-wizard/components/Dropdown.js
 create mode 100644 packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss
 create mode 100644 packages/xpub-faraday/app/component-wizard/components/Steps.js
 create mode 100644 packages/xpub-faraday/app/component-wizard/components/Steps.local.scss

diff --git a/packages/xpub-faraday/app/component-wizard/components/Dropdown.js b/packages/xpub-faraday/app/component-wizard/components/Dropdown.js
new file mode 100644
index 000000000..e2e124cda
--- /dev/null
+++ b/packages/xpub-faraday/app/component-wizard/components/Dropdown.js
@@ -0,0 +1,67 @@
+import React from 'react'
+import { compose, withState, withHandlers } from 'recompose'
+import classnames from 'classnames'
+
+import classes from './Dropdown.local.scss'
+
+const DropdownOptions = ({ visible, options, onSelect }) =>
+  visible ? (
+    <div className={classes.options}>
+      {options.map(opt => (
+        <div key={opt.value} onClick={onSelect(opt)}>
+          {opt.label}
+        </div>
+      ))}
+    </div>
+  ) : null
+
+const Dropdown = ({
+  label,
+  showDropdown,
+  inputValue,
+  changeInput,
+  defaultValue = null,
+  options,
+  onChange,
+  setDropdown,
+  selectValue,
+}) => (
+  <div className={classes.container}>
+    <span className={classes.label}>{label}</span>
+    <div className={classes.inputContainer}>
+      <input
+        onChange={changeInput}
+        onFocus={setDropdown(true)}
+        placeholder="Type or select from dropdown"
+        type="text"
+        value={inputValue.label}
+      />
+      <span className={classnames({ [classes.downarrow]: showDropdown })}>
+        &#9658;
+      </span>
+    </div>
+    <DropdownOptions
+      onSelect={selectValue}
+      options={options.filter(opt => opt.label.indexOf(inputValue.label) > -1)}
+      visible={showDropdown}
+    />
+  </div>
+)
+
+export default compose(
+  withState('inputValue', 'setInputValue', ({ defaultValue }) => defaultValue),
+  withState('showDropdown', 'setDropdownVisibility', false),
+  withHandlers({
+    changeInput: ({ setInputValue }) => e => {
+      e.persist()
+      setInputValue(prev => ({ ...prev, label: e.target.value }))
+    },
+    setDropdown: ({ setDropdownVisibility }) => visibilty => e => {
+      setDropdownVisibility(visibilty)
+    },
+    selectValue: ({ setInputValue, setDropdownVisibility }) => value => e => {
+      setInputValue(value)
+      setDropdownVisibility(false)
+    },
+  }),
+)(Dropdown)
diff --git a/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss b/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss
new file mode 100644
index 000000000..ffe230262
--- /dev/null
+++ b/packages/xpub-faraday/app/component-wizard/components/Dropdown.local.scss
@@ -0,0 +1,57 @@
+.container {
+  display: flex;
+  flex-direction: column;
+  margin: 5px 0;
+  position: relative;
+}
+
+.label {
+  font-size: 16px;
+  font-weight: 400;
+  margin: 5px 0;
+}
+
+.inputContainer {
+  align-items: center;
+  display: flex;
+  position: relative;
+
+  input {
+    border: 1px solid #888;
+    border-radius: 2px;
+    display: flex;
+    flex: 1;
+    height: 20px;
+    padding: 0 2px;
+
+    &:focus {
+      outline: none;
+    }
+  }
+
+  span {
+    position: absolute;
+    right: 10px;
+    top: 1px;
+    transform: rotateZ(90deg);
+    transition: transform 0.2s linear;
+  }
+}
+
+.options {
+  background-color: #eee;
+  cursor: pointer;
+  left: 0;
+  position: absolute;
+  top: 50px;
+  width: 100%;
+  z-index: 1000;
+
+  :hover {
+    background-color: #aaa;
+  }
+}
+
+.downarrow {
+  transform: rotateZ(270deg) !important;
+}
diff --git a/packages/xpub-faraday/app/component-wizard/components/Steps.js b/packages/xpub-faraday/app/component-wizard/components/Steps.js
new file mode 100644
index 000000000..01b18ae28
--- /dev/null
+++ b/packages/xpub-faraday/app/component-wizard/components/Steps.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { compose, withHandlers, withContext, getContext } from 'recompose'
+
+import classes from './Steps.local.scss'
+
+const Separator = () => <div className={classes.separator} />
+
+const Step = ({ title, index, currentStep }) => (
+  <div className={classes.step}>
+    {index <= currentStep && <div className={classes.bullet} />}
+    <span className={classes.stepTitle}>{`${index + 1}. ${title}`}</span>
+  </div>
+)
+
+const Steps = ({ currentStep, children, renderSeparator, renderSteps }) => (
+  <div className={classes.container}>{renderSteps()}</div>
+)
+
+const DecoratedSteps = compose(
+  withHandlers({
+    renderSteps: ({ children, currentStep }) => () => {
+      const c = []
+      React.Children.forEach(children, (child, idx) => {
+        c.push(child)
+        if (idx !== React.Children.count(children) - 1) {
+          c.push(<Separator key={Math.random()} />)
+        }
+      })
+      return c
+    },
+  }),
+  withContext({ currentStep: PropTypes.number }, ({ currentStep }) => ({
+    currentStep,
+  })),
+)(Steps)
+
+DecoratedSteps.Step = getContext({ currentStep: PropTypes.number })(Step)
+
+export default DecoratedSteps
diff --git a/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss b/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss
new file mode 100644
index 000000000..887b70766
--- /dev/null
+++ b/packages/xpub-faraday/app/component-wizard/components/Steps.local.scss
@@ -0,0 +1,41 @@
+.container {
+  align-items: center;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin: 0 40px;
+  min-width: 400px;
+}
+
+.separator {
+  background-color: #444;
+  flex: 1;
+  height: 2px;
+}
+
+.step {
+  align-items: center;
+  border: 2px solid #555;
+  border-radius: 50%;
+  display: flex;
+  height: 16px;
+  justify-content: center;
+  position: relative;
+  width: 16px;
+}
+
+.bullet {
+  background-color: #555;
+  border-radius: 50%;
+  height: 10px;
+  width: 10px;
+}
+
+.stepTitle {
+  font-size: 14px;
+  left: -40px;
+  position: absolute;
+  top: 25px;
+  white-space: normal;
+  width: 120px;
+}
diff --git a/packages/xpub-faraday/app/component-wizard/components/Wizard.js b/packages/xpub-faraday/app/component-wizard/components/Wizard.js
index af2abb592..37f1fe26c 100644
--- a/packages/xpub-faraday/app/component-wizard/components/Wizard.js
+++ b/packages/xpub-faraday/app/component-wizard/components/Wizard.js
@@ -1,32 +1,37 @@
 import React from 'react'
-import { compose, withHandlers } from 'recompose'
+import { compose, withHandlers, withState } from 'recompose'
 import { withJournal } from 'xpub-journal'
 
-const Wizard = ({ journal: { wizard }, renderStep }) => (
+import { Dropdown, Steps } from '../'
+
+const { Step } = Steps
+
+const options = [
+  { label: 'opt 1', value: 'opt1' },
+  { label: 'caca 2', value: 'opt2' },
+  { label: 'maca 3', value: 'opt3' },
+  { label: 'vaca 4', value: 'opt4' },
+]
+
+const Wizard = ({ journal: { wizard }, getSteps, step, incrementStep }) => (
   <div>
-    {wizard.map((e, i) => (
-      <div key={Math.random()}>
-        {e.label} - {e.title}
-        {e.children && e.children.map((c, i) => renderStep(c.type))}
-      </div>
-    ))}
+    <Dropdown defaultValue={options[0]} label="My dropdown" options={options} />
+    <Dropdown defaultValue={options[1]} label="Altceva" options={options} />
+    <Dropdown defaultValue={options[3]} label="Trei" options={options} />
+    <button onClick={incrementStep}>Increment step</button>
+    <Steps currentStep={step}>
+      {getSteps().map((step, index) => (
+        <Step index={index} key={step} title={step} />
+      ))}
+    </Steps>
   </div>
 )
 
 export default compose(
+  withJournal,
+  withState('step', 'changeStep', 0),
   withHandlers({
-    renderStep: props => type => {
-      switch (type) {
-        case 'dropdown':
-          return <div>render dropdown</div>
-        case 'radio':
-          return <div>render radio</div>
-        case 'checkbox':
-          return <div>render checkbox</div>
-        default:
-          return null
-      }
-    },
+    getSteps: ({ journal: { wizard } }) => () => wizard.map(w => w.label),
+    incrementStep: ({ changeStep }) => () => changeStep(step => step + 1),
   }),
-  withJournal,
 )(Wizard)
diff --git a/packages/xpub-faraday/app/component-wizard/index.js b/packages/xpub-faraday/app/component-wizard/index.js
index 88e2a880e..142a3246f 100644
--- a/packages/xpub-faraday/app/component-wizard/index.js
+++ b/packages/xpub-faraday/app/component-wizard/index.js
@@ -1 +1,3 @@
+export { default as Steps } from './components/Steps'
 export { default as Wizard } from './components/Wizard'
+export { default as Dropdown } from './components/Dropdown'
-- 
GitLab