Initial commit

This commit is contained in:
Nawaz Dhandala 2019-08-02 18:26:16 +05:30
commit 08004aaf68
No known key found for this signature in database
GPG Key ID: 43C184A0DB24F9F6
1561 changed files with 425696 additions and 0 deletions

96
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,96 @@
# IMPORTANT:
#
# This CI/CD will run on an Ubuntu VM. After this script runs, the VM will retain the state.
# It's your responsibility to clean the VM up in the cleanup stage after job finishes executing.
# This script runs on Microk8s. since our deployments are on Kubernetes, our aim is to create EXACT same replica for test, staging and production.
#Define stages
stages:
- build_n_test
- e2e_test
- deploy_staging
- deploy_production
build_n_test:
stage: build_n_test
script:
- sudo docker stop $(sudo docker ps -aq) || echo 'No docker containers'
- sudo docker rm $(sudo docker ps -aq) || echo 'No docker containers'
- sudo docker run --name mongo -p 27017:27017 -d mongo:3.4
- cd backend
- sudo docker build -t fyipe-project/backend:1.0.$CI_PIPELINE_IID .
- sudo docker run --name fyipe --network container:mongo fyipe-project/backend:1.0.$CI_PIPELINE_IID npm test
- cd ..
e2e_test:
stage: e2e_test
script:
- cd kubernetes
- chmod +x ./ci/setup-machine.sh
- ./ci/setup-machine.sh
- chmod +x ./ci/setup.sh
- ./ci/setup.sh
- BACKEND_CONTAINER_NAME=`sudo kubectl get pods -l app=backend -o custom-columns=:metadata.name`
- sudo kubectl get pod BACKEND_CONTAINER_NAME=
only:
refs:
- release
- master
deploy_staging:
stage: deploy_staging
script:
- cd kubernetes
- chmod +x ./ci/deployment-setup.sh
- ./ci/deployment-setup.sh
- chmod +x ./ci/deployment-staging-setup.sh
- ./ci/deployment-staging-setup.sh
- cd ..
- git clone https://$GIT_USERNAME:$GIT_PASSWORD@gitlab.com/fyipe-project/backend.git
- cd backend
- git checkout master
- sudo docker build -t fyipe-project/backend:master .
- sudo docker tag fyipe-project/backend:master registry.gitlab.com/fyipe-project/backend:2.0.$CI_PIPELINE_IID
- sudo docker tag fyipe-project/backend:master registry.gitlab.com/fyipe-project/backend:master
- sudo docker push registry.gitlab.com/fyipe-project/backend:2.0.$CI_PIPELINE_IID
- sudo docker push registry.gitlab.com/fyipe-project/backend:master
- sudo $HOME/google-cloud-sdk/bin/kubectl set image deployment/backend backend=registry.gitlab.com/fyipe-project/backend:2.0.$CI_PIPELINE_IID
- cd ..
- cd kubernetes
- chmod +x ./ci/deployment-cleanup.sh
- ./ci/deployment-cleanup.sh
only:
refs:
- master
environment:
name: staging
deploy_production:
stage: deploy_production
script:
- sudo rm -r *
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/fyipe-project/kubernetes
- cd kubernetes
- chmod +x ./ci/deployment-setup.sh
- ./ci/deployment-setup.sh
- chmod +x ./ci/deployment-production-setup.sh
- ./ci/deployment-production-setup.sh
- cd ..
- git clone https://$GIT_USERNAME:$GIT_PASSWORD@gitlab.com/fyipe-project/backend.git
- cd backend
- git checkout release
- sudo docker build -t fyipe-project/backend:latest .
- sudo docker tag fyipe-project/backend:latest registry.gitlab.com/fyipe-project/backend:1.0.$CI_PIPELINE_IID
- sudo docker tag fyipe-project/backend:latest registry.gitlab.com/fyipe-project/backend:latest
- sudo docker push registry.gitlab.com/fyipe-project/backend:1.0.$CI_PIPELINE_IID
- sudo docker push registry.gitlab.com/fyipe-project/backend:latest
- sudo $HOME/google-cloud-sdk/bin/kubectl set image deployment/backend backend=registry.gitlab.com/fyipe-project/backend:1.0.$CI_PIPELINE_IID
- cd ..
- cd kubernetes
- chmod +x ./ci/deployment-cleanup.sh
- ./ci/deployment-cleanup.sh
only:
refs:
- release
environment:
name: production

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# Fyipe Project

3
accounts/.babelrc Executable file
View File

@ -0,0 +1,3 @@
{
"plugins": ["loadable-components/babel"]
}

2
accounts/.dockerignore Executable file
View File

@ -0,0 +1,2 @@
node_modules
build

4
accounts/.eslintignore Executable file
View File

@ -0,0 +1,4 @@
/node_modules
/build
/coverage
*.test.js

77
accounts/.eslintrc.json Executable file
View File

@ -0,0 +1,77 @@
{
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true,
"spread": true
},
"sourceType": "module"
},
"env": {
"browser": true,
"node": true,
"jquery": true,
"es6": true
},
"plugins": [
"react"
],
"extends": ["eslint:recommended", "plugin:react/recommended"],
"parser": "babel-eslint",
"rules": {
"no-fallthrough": "error",
"no-unreachable": "error",
"no-cond-assign": "error",
"no-console": "error",
"valid-typeof": "error",
"no-func-assign": "error",
"no-extra-semi": "error",
"no-unused-vars": [
"error",
{
"varsIgnorePattern": "[iI]gnored",
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": true,
"argsIgnorePattern": "[iI]gnored"
}
],
"no-undef": "error",
"no-empty": "error",
"no-case-declarations": "error",
"no-mixed-spaces-and-tabs": "error",
"no-useless-escape": "error",
"react/jsx-no-undef": "error",
"quotes": ["error", "single"],
"react/jsx-no-bind": ["error", {
"allowArrowFunctions": true,
"allowBind": false,
"ignoreRefs": false
}],
"react/no-children-prop": "error",
"react/no-deprecated": "error",
"react/no-array-index-key": "off",
"react/boolean-prop-naming": "error",
"react/no-is-mounted": "error",
"react/no-find-dom-node": "error",
"react/no-did-update-set-state": "error",
"react/no-unknown-property": "error",
"react/no-unused-prop-types": "error",
"react/jsx-no-duplicate-props": "error",
"react/no-unused-state": "error",
"react/jsx-uses-vars": "error",
"react/prop-types": "error",
"react/react-in-jsx-scope": "error",
"react/no-string-refs": "warn",
"jsx-a11y/href-no-hash": [0],
"react/no-unescaped-entities": "error",
"react/display-name": ["error", {
"ignoreTranspilerName": true
}]
}
}

26
accounts/.gitignore vendored Executable file
View File

@ -0,0 +1,26 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
.vscode/
.idea
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn.lock
Untitled-1

99
accounts/.gitlab-ci.yml Executable file
View File

@ -0,0 +1,99 @@
# IMPORTANT:
#
# This CI/CD will run on an Ubuntu VM. After this script runs, the VM will retain the state.
# It's your responsibility to clean the VM up in the cleanup stage after job finishes executing.
# This script runs on Minikube. since our deployments are on Kubernetes, our aim is to create EXACT same replica for test, staging and production.
#Define statges
stages:
- setup_environment
- build_n_test
- deploy_staging
- deploy_production
- cleanup
- deployment_cleanup
before_script:
- sudo rm -r *
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/fyipe-project/kubernetes
- cd kubernetes
#Set up the environment
setup_environment:
stage: setup_environment
script:
- chmod +x ./ci/setup-machine.sh
- ./ci/setup-machine.sh
build_n_test:
stage: build_n_test
script:
- chmod +x ./ci/setup.sh
- ./ci/setup.sh
- ACCOUNTS_CONTAINER=`sudo kubectl get pods -l app=accounts -o custom-columns=:metadata.name`
- sudo kubectl exec $ACCOUNTS_CONTAINER -- npm test
deploy_staging:
stage: deploy_staging
script:
- chmod +x ./ci/deployment-setup.sh
- ./ci/deployment-setup.sh
- chmod +x ./ci/deployment-staging-setup.sh
- ./ci/deployment-staging-setup.sh
- cd ..
- git clone https://$GIT_USERNAME:$GIT_PASSWORD@gitlab.com/fyipe-project/accounts.git
- cd accounts
- git checkout master
- sudo docker build -t fyipe-project/accounts:master .
- sudo docker tag fyipe-project/accounts:master registry.gitlab.com/fyipe-project/accounts:2.0.$CI_PIPELINE_IID
- sudo docker tag fyipe-project/accounts:master registry.gitlab.com/fyipe-project/accounts:master
- sudo docker push registry.gitlab.com/fyipe-project/accounts:2.0.$CI_PIPELINE_IID
- sudo docker push registry.gitlab.com/fyipe-project/accounts:master
- sudo $HOME/google-cloud-sdk/bin/kubectl set image deployment/accounts accounts=registry.gitlab.com/fyipe-project/accounts:2.0.$CI_PIPELINE_IID
only:
refs:
- master
environment:
name: staging
deploy_production:
stage: deploy_production
script:
- chmod +x ./ci/deployment-setup.sh
- ./ci/deployment-setup.sh
- chmod +x ./ci/deployment-production-setup.sh
- ./ci/deployment-production-setup.sh
- cd ..
- git clone https://$GIT_USERNAME:$GIT_PASSWORD@gitlab.com/fyipe-project/accounts.git
- cd accounts
- git checkout release
- sudo docker build -t fyipe-project/accounts:latest .
- sudo docker tag fyipe-project/accounts:latest registry.gitlab.com/fyipe-project/accounts:1.0.$CI_PIPELINE_IID
- sudo docker tag fyipe-project/accounts:latest registry.gitlab.com/fyipe-project/accounts:latest
- sudo docker push registry.gitlab.com/fyipe-project/accounts:1.0.$CI_PIPELINE_IID
- sudo docker push registry.gitlab.com/fyipe-project/accounts:latest
- sudo $HOME/google-cloud-sdk/bin/kubectl set image deployment/accounts accounts=registry.gitlab.com/fyipe-project/accounts:1.0.$CI_PIPELINE_IID
only:
refs:
- release
environment:
name: production
cleanup_job:
stage: cleanup
script:
- chmod +x ./ci/cleanup.sh
- ./ci/cleanup.sh
when: always
deployment_cleanup:
stage: deployment_cleanup
script:
- chmod +x ./ci/deployment-cleanup.sh
- ./ci/deployment-cleanup.sh
only:
refs:
- release
- master
when: always

30
accounts/Dockerfile Executable file
View File

@ -0,0 +1,30 @@
#
# Accounts Dockerfile
#
# Pull base image nodejs image.
FROM node:10
#SET ENV Variables
ENV PRODUCTION=true
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Install app dependencies
COPY package*.json /usr/src/app/
RUN npm install
# Copy app source
COPY . /usr/src/app
# Bundle app source
RUN npm run build
# Expose ports.
# - 3003: accounts
EXPOSE 3003
#Run the app
CMD [ "npm", "start" ]

38
accounts/README.md Executable file
View File

@ -0,0 +1,38 @@
# Fyipe Dashboard - Accounts
Repository for user authentication of the fyipe dashboard
## Stack
- Reactjs - UI Library
- Redux - State managment
- Redux Forms - Forms
## Start
To run the app:
```
npm install
```
In development:
```
npm run dev
```
In production:
```
npm start
```
## Puppeteer Tests
To run puppeteer tests for this repo, follow these steps:
- Start the backend server
- Start the accounts application
- Then run ```npm run jest``` from your terminal

11
accounts/index.js Executable file
View File

@ -0,0 +1,11 @@
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(3003);

16032
accounts/package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

114
accounts/package.json Executable file
View File

@ -0,0 +1,114 @@
{
"name": "fyipe-accounts",
"version": "0.1.0",
"private": true,
"dependencies": {
"@trendmicro/react-dropdown": "^1.3.0",
"axios": "^0.18.0",
"browserslist": "^4.6.1",
"card-validator": "^4.3.0",
"chart.js": "^2.7.2",
"clipboard": "^2.0.1",
"cloudboost": "^6.6.6",
"components": "^0.1.0",
"connected-react-router": "^4.5.0",
"creditcard-generator": "0.0.7",
"express": "^4.16.4",
"faker": "^4.1.0",
"file-saver": "^2.0.1",
"fuzzy-match-utils": "^1.3.0",
"history": "^4.7.2",
"humanize-duration": "^3.15.3",
"jest": "^24.7.1",
"js-uuid": "0.0.6",
"jshint": "^2.9.6",
"loadable": "^1.0.0",
"loadable-components": "^2.2.3",
"loaders.css": "^0.1.2",
"lodash": "^4.17.5",
"material-ui": "^0.20.0",
"mixpanel-browser": "^2.22.3",
"mockdate": "^2.0.2",
"moment": "^2.22.2",
"moment-range": "^4.0.1",
"prop-types": "^15.6.1",
"puppeteer": "^1.17.0",
"query-string": "^5.1.1",
"react": "^16.5.2",
"react-click-outside": "github:tj/react-click-outside",
"react-daterange-picker": "^2.0.1",
"react-dom": "^16.5.2",
"react-frontload": "^1.0.3",
"react-ga": "^2.5.3",
"react-hover-observer": "^2.1.0",
"react-loadable": "^5.5.0",
"react-loaders": "^3.0.1",
"react-mixpanel": "0.0.11",
"react-moment-proptypes": "^1.6.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
"react-scripts": "^3.0.1",
"react-select-fyipe": "^2.1.8",
"react-stripe-elements": "^1.6.0",
"react-widgets": "^4.4.9",
"react-with-direction": "^1.3.0",
"recharts": "^1.3.0",
"redux": "^3.7.2",
"redux-axios-middleware": "^4.0.0",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0",
"sane-email-validation": "^1.1.0",
"should": "^13.2.3",
"to-pascal-case": "^1.0.0",
"universal-cookie": "^4.0.0",
"valid-url": "^1.0.9"
},
"scripts": {
"lint": "eslint .",
"dev": "export PORT=3003 && react-scripts start",
"build": "react-scripts build",
"test": "npm run lint",
"jest": "jest src/test/index.test.js",
"start": "node index.js",
"audit": "npm-audit-ci-wrapper --threshold=high"
},
"devDependencies": {
"axios-mock-adapter": "^1.15.0",
"babel-core": "^6.26.3",
"babel-loader": "8.0.5",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"cross-env": "^5.2.0",
"eslint": "5.16.0",
"jest-localstorage-mock": "^2.2.0",
"npm-audit-ci-wrapper": "^2.2.1",
"react-test-renderer": "^16.5.2",
"redux-logger": "^3.0.6",
"redux-mock-store": "^1.5.3",
"webpack": "^4.29.6"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.js",
"!src/**/*.stories.js",
"!src/store.js",
"!src/config.js",
"!src/routes.js",
"!src/setupTests.js"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -0,0 +1,10 @@
#login .selector {
font-size: 18px;
padding: 10px 12px;
width: 100%;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18);
border: 1px solid #ddd;
background-color: #fff;
box-sizing: border-box;
height: 45px;
}

View File

@ -0,0 +1,201 @@
/******* Row containing Bar Chart *******/
/******* Simple Bar Chart *******/
div.block-chart-main{
position: relative;
height: 75px;
margin-top:-15px;
margin-left:10px;
}
.db-Trend-colInformation{
margin-right: 8px;
}
div.block-chart {
position: relative;
height: 75px;
float: right;
overflow: hidden;
width: 101%; /* IE overflow fix */
}
div.block-chart div.bar {
float: left;
position: relative;
height: 100%;
width: 6px;
cursor: pointer;
/* Border instead of margin so we get the hover behavior we want */
border-left: 1px solid #fff;
border-right: 1px solid #fff;
/* DEFAULT IS GREEN */
background: rgb(0, 128, 168);
}
div.block-chart div.bar:hover {
opacity: 1.0;
}
div.block-chart div.bar.empty {
float: left;
position: relative;
height: 100%;
width: 6px;
cursor: pointer;
/* Border instead of margin so we get the hover behavior we want */
border-left: 1px solid #fff;
border-right: 1px solid #fff;
opacity: 0.6;
/* DEFAULT IS GREEN */
background: rgb(0, 128, 168);
}
div.block-chart div.bar.empty:hover {
opacity: 1.0;
}
div.block-chart div.bar.mid {
background: #FFDE24;
}
div.block-chart div.bar.down {
background: #FA6D46;
}
div.block-chart div.bar:first-child {
border-left: 0;
}
div.block-chart div.bar:last-child {
border-right: 0;
}
******* Tipsy Tooltips ******/
.tipsy {
font-size: 12px;
position: absolute;
padding: 5px;
z-index: 100000;
}
.tipsy-inner {
background-color: #32325d;
color: #FFF;
max-width: 200px;
padding: 5px 12px 5px 12px;
line-height: 19px;
text-align: center;
}
/* Rounded corners */
.tipsy-inner {
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
/* Uncomment for shadow */
/*.tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }*/
.tipsy-arrow {
position: absolute;
width: 0;
height: 0;
line-height: 0;
border: 5px dashed #32325d;
}
/* Rules to colour arrows */
.tipsy-arrow-n {
border-bottom-color: #32325d;
}
.tipsy-arrow-s {
border-top-color: #32325d;
}
.tipsy-arrow-e {
border-left-color: #32325d;
}
.tipsy-arrow-w {
border-right-color: #32325d;
}
.tipsy-n .tipsy-arrow {
top: 0px;
left: 50%;
margin-left: -5px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-nw .tipsy-arrow {
top: 0;
left: 10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-ne .tipsy-arrow {
top: 0; right: 10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-s .tipsy-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-sw .tipsy-arrow {
bottom: 0; left: 10px;
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-se .tipsy-arrow {
bottom: 0;
right: 10px;
border-top-style: solid;
border-bottom: none;
border-left-color: transparent;
border-right-color: transparent;
}
.tipsy-e .tipsy-arrow {
right: 0;
top: 50%;
margin-top: -5px;
border-left-style: solid;
border-right: none;
border-top-color: transparent;
border-bottom-color: transparent;
}
.tipsy-w .tipsy-arrow {
left: 0;
top: 50%;
margin-top: -5px;
border-right-style: solid;
border-left: none;
border-top-color: transparent;
border-bottom-color: transparent;
}
@media only screen and (max-width: 1180px) {
div.block-chart div.bar {
width: 5px;
}
div.block-chart div.bar.empty {
width: 5px;
}
.chart-font{
font-size: 90%;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,974 @@
.rw-btn,
.rw-input-reset,
.rw-input,
.rw-dropdown-list-autofill,
.rw-filter-input {
color: inherit;
padding: 0;
margin: 0;
border: none;
box-shadow: none;
background: none;
background-image: none;
font-family: inherit;
font-size: inherit;
line-height: inherit;
-ms-touch-action: manipulation;
touch-action: manipulation
}
.rw-btn::-moz-focus-inner {
padding: 0;
border: 0
}
select.rw-input {
text-transform: none
}
html input[type="button"].rw-input {
-webkit-appearance: button;
cursor: pointer
}
textarea.rw-input {
overflow: auto;
resize: vertical
}
button[disabled].rw-input,
fieldset[disabled] .rw-input,
html input[disabled].rw-input {
cursor: not-allowed
}
button.rw-input::-moz-focus-inner,
input.rw-input::-moz-focus-inner {
border: 0;
padding: 0
}
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box;
padding: 0
}
@font-face {
font-family: 'RwWidgets';
font-weight: normal;
font-style: normal;
src: url('../fonts/rw-widgets.eot?v=4.1.0');
src: url('../fonts/rw-widgets.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('../fonts/rw-widgets.woff?v=4.1.0') format('woff'), url('../fonts/rw-widgets.ttf?v=4.1.0') format('truetype'), url('../fonts/rw-widgets.svg?v=4.1.0#fontawesomeregular') format('svg')
}
.rw-i {
display: inline-block;
color: inherit;
font-family: RwWidgets;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased
}
.rw-i-caret-down:before {
content: '\e803'
}
.rw-i-caret-up:before {
content: '\e800'
}
.rw-i-chevron-left:before {
content: '\f104'
}
.rw-i-chevron-right:before {
content: '\f105'
}
.rw-i-clock-o:before {
content: '\e805'
}
.rw-i-calendar:before {
content: '\e804'
}
.rw-i-search:before {
content: '\e801'
}
.rw-btn {
position: relative;
color: #333;
display: inline-block;
text-align: center;
vertical-align: middle;
border: 1px solid transparent;
cursor: pointer;
outline: none
}
.rw-state-readonly .rw-btn,
.rw-state-disabled .rw-btn {
cursor: not-allowed
}
.rw-btn-select {
opacity: .75;
filter: alpha(opacity=75);
transition: opacity 150ms ease-in
}
.rw-btn-select:hover,
.rw-state-focus .rw-btn-select,
:hover>.rw-btn-select {
opacity: 1;
filter: alpha(opacity=100)
}
.rw-btn-primary {
width: 100%;
white-space: normal;
line-height: 2em
}
.rw-btn-primary:hover {
background-color: #e6e6e6
}
.rw-btn-select[disabled],
.rw-btn-primary[disabled],
fieldset[disabled] .rw-btn-select,
fieldset[disabled] .rw-btn-primary {
box-shadow: none;
cursor: not-allowed;
opacity: .65;
filter: alpha(opacity=65);
pointer-events: none
}
.rw-sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0
}
.rw-widget {
background-clip: border-box;
border: none;
color: #333;
font-size: 1em;
font-family: inherit;
outline: none;
position: relative
}
.rw-widget,
.rw-widget * {
box-sizing: border-box
}
.rw-widget:before,
.rw-widget *:before,
.rw-widget:after,
.rw-widget *:after {
box-sizing: border-box
}
.rw-widget>.rw-widget-container {
width: 100%;
margin: 0
}
.rw-widget-container {
background-color: #fff;
border: #ccc 1px solid;
border-radius: 4px
}
.rw-widget-container.rw-state-focus,
.rw-state-focus>.rw-widget-container,
.rw-widget-container.rw-state-focus:hover,
.rw-state-focus>.rw-widget-container:hover {
background-color: #fff;
box-shadow: 0 0 8px rgba(102, 175, 233, 0.6)
}
.rw-widget-container.rw-state-readonly,
.rw-state-readonly>.rw-widget-container {
cursor: not-allowed
}
.rw-widget-container.rw-state-disabled,
.rw-state-disabled>.rw-widget-container,
fieldset[disabled] .rw-widget-container,
.rw-widget-container.rw-state-disabled:hover,
.rw-state-disabled>.rw-widget-container:hover,
fieldset[disabled] .rw-widget-container:hover,
.rw-widget-container.rw-state-disabled:active,
.rw-state-disabled>.rw-widget-container:active,
fieldset[disabled] .rw-widget-container:active {
box-shadow: none;
cursor: not-allowed
}
.rw-widget-picker {
position: relative;
overflow: hidden;
border-collapse: separate;
display: inline-table;
height: 2.429em
}
.rw-widget-picker>* {
position: relative;
border: none;
outline: none;
width: 100%;
height: 100%;
display: table-cell
}
.rw-widget-picker>.rw-select {
width: 1%;
white-space: nowrap
}
.rw-open>.rw-widget-picker {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0
}
.rw-open-up>.rw-widget-picker {
border-top-right-radius: 0;
border-top-left-radius: 0
}
fieldset[disabled] .rw-widget-picker,
.rw-state-disabled>.rw-widget-picker {
background-color: #eee
}
.rw-select {
cursor: pointer
}
.rw-select>* {
width: 1.9em;
height: 100%
}
.rw-state-readonly .rw-select,
.rw-state-disabled .rw-select {
cursor: not-allowed
}
.rw-select-bordered {
cursor: pointer;
border: none;
border-left: #ccc 1px solid
}
.rw-select-bordered:hover,
.rw-select-bordered:active {
background-color: #e6e6e6
}
.rw-select-bordered:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.rw-state-disabled .rw-select-bordered,
.rw-state-readonly .rw-select-bordered,
fieldset[disabled] .rw-select-bordered,
.rw-state-disabled .rw-select-bordered:hover,
.rw-state-readonly .rw-select-bordered:hover,
fieldset[disabled] .rw-select-bordered:hover,
.rw-state-disabled .rw-select-bordered:active,
.rw-state-readonly .rw-select-bordered:active,
fieldset[disabled] .rw-select-bordered:active {
cursor: not-allowed;
background-color: inherit;
background-image: none;
box-shadow: none
}
.rw-rtl .rw-select-bordered {
border-right: #ccc 1px solid;
border-left: none
}
.rw-rtl {
direction: rtl
}
.rw-input-reset,
.rw-input,
.rw-dropdown-list-autofill,
.rw-filter-input {
outline: 0
}
.rw-input-reset::-moz-placeholder {
color: #999;
opacity: 1
}
.rw-input-reset:-ms-input-placeholder {
color: #999
}
.rw-input-reset::-webkit-input-placeholder {
color: #999
}
.rw-input,
.rw-dropdown-list-autofill,
.rw-filter-input {
color: #555;
padding: 0 .857em;
background-color: #fff
}
.rw-input[type='text']::-ms-clear {
display: none
}
.rw-input[disabled],
fieldset[disabled] .rw-input {
box-shadow: none;
cursor: not-allowed;
opacity: 1;
background-color: #eee;
border-color: #ccc
}
.rw-input[readonly] {
cursor: not-allowed
}
.rw-i.rw-loading {
display: block;
background: url('../img/loading.gif') no-repeat center;
min-width: 16px;
width: 1.9em;
height: 16px
}
.rw-i.rw-loading:before {
content: ''
}
.rw-placeholder {
color: #999
}
.rw-detect-autofill:-webkit-autofill {
animation-name: react-widgets-autofill-start;
transition: background-color 50000s ease-in-out 0s
}
.rw-detect-autofill:not(:-webkit-autofill) {
animation-name: react-widgets-autofill-cancel
}
.rw-webkit-autofill .rw-widget-container,
.rw-input:-webkit-autofill {
background-color: #faffbd !important;
background-image: none !important;
color: #000 !important
}
.rw-widget-input,
.rw-filter-input {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075)
}
.rw-widget-input.rw-state-focus {
box-shadow: 0 0 8px rgba(102, 175, 233, 0.6), inset 0 1px 1px rgba(0, 0, 0, 0.075)
}
.rw-list {
margin: 0;
padding: 0;
list-style: none;
font-size: 1em;
outline: 0;
overflow: auto;
max-height: 200px
}
.rw-list-option {
-ms-user-select: none;
user-select: none;
color: #333;
cursor: pointer;
border: 1px solid transparent
}
.rw-list-option.rw-state-focus,
.rw-list-option.rw-state-focus:hover {
background-color: transparent;
color: #333
}
.rw-list-option:hover,
.rw-list-option:hover.rw-state-focus {
background-color: #e6e6e6;
border-color: #e6e6e6;
color: #333
}
.rw-list-option.rw-state-selected,
.rw-list-option.rw-state-selected:hover {
background-color: #337ab7;
border-color: #337ab7;
color: white
}
fieldset[disabled] .rw-list-option,
.rw-list-option.rw-state-disabled,
.rw-list-option.rw-state-readonly {
box-shadow: none;
cursor: not-allowed;
color: #999;
filter: alpha(opacity=7);
opacity: .7
}
fieldset[disabled] .rw-list-option:hover,
.rw-list-option.rw-state-disabled:hover,
.rw-list-option.rw-state-readonly:hover {
background: none;
border-color: transparent
}
.rw-list-empty,
.rw-list-option,
.rw-list-optgroup {
padding: .143em .75em;
outline: 0
}
.rw-list-optgroup {
font-weight: bold;
padding-top: 7px
}
.rw-list-option-create {
border-top: 1px #ccc solid
}
.rw-dropdown-list-autofill {
padding: 0
}
.rw-dropdown-list-input {
background-color: transparent;
vertical-align: middle;
padding-right: 0;
max-width: 1px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden
}
.rw-rtl .rw-dropdown-list-input {
padding-right: .857em;
padding-left: 0
}
.rw-filter-input {
position: relative;
margin: 4px;
padding-right: 0
}
.rw-filter-input .rw-rtl {
padding-right: .857em;
padding-left: 0
}
.rw-filter-input .rw-select,
.rw-filter-input .rw-btn {
opacity: .75;
filter: alpha(opacity=75);
cursor: text
}
.rw-filter-input>.rw-select,
.rw-filter-input>.rw-select:active,
.rw-filter-input>.rw-select:hover {
background: none;
cursor: initial;
box-shadow: none
}
.rw-number-picker .rw-btn {
cursor: pointer;
height: calc(1.2145em - 1px);
margin-top: -1px\9;
height: 1.2145em\9;
line-height: 1.2145em;
line-height: calc(1.2145em - 1px);
display: block;
border: none
}
.rw-number-picker .rw-btn:hover,
.rw-number-picker .rw-btn:active {
background-color: #e6e6e6
}
.rw-number-picker .rw-btn:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125)
}
.rw-state-disabled .rw-number-picker .rw-btn,
.rw-state-readonly .rw-number-picker .rw-btn,
fieldset[disabled] .rw-number-picker .rw-btn,
.rw-state-disabled .rw-number-picker .rw-btn:hover,
.rw-state-readonly .rw-number-picker .rw-btn:hover,
fieldset[disabled] .rw-number-picker .rw-btn:hover,
.rw-state-disabled .rw-number-picker .rw-btn:active,
.rw-state-readonly .rw-number-picker .rw-btn:active,
fieldset[disabled] .rw-number-picker .rw-btn:active {
cursor: not-allowed;
background-color: inherit;
background-image: none;
box-shadow: none
}
.rw-number-picker .rw-select {
vertical-align: middle
}
.rw-number-picker .rw-select,
.rw-number-picker .rw-select:hover,
.rw-number-picker .rw-select:active {
box-shadow: none
}
.rw-calendar-popup {
right: auto;
min-width: 0;
width: 18em
}
.rw-calendar {
border-radius: 4px;
background-color: #fff;
border: #ccc 1px solid;
overflow: hidden
}
.rw-calendar.rw-popup {
border-color: #ccc
}
.rw-calendar-now {
font-weight: bold
}
.rw-calendar-btn-left,
.rw-calendar-btn-right {
width: 12.5%
}
.rw-calendar-btn-view {
width: 75%
}
.rw-calendar-footer {
border-top: 1px solid #ccc
}
.rw-calendar-grid {
outline: none;
height: 14.28571429em;
table-layout: fixed;
border-collapse: separate;
border-spacing: 0;
width: 100%;
background-color: #fff
}
.rw-head-cell {
text-align: center;
border-bottom: 1px solid #ccc;
padding: .25em
}
.rw-cell {
color: #333;
border-radius: 4px;
cursor: pointer;
line-height: normal;
text-align: center;
border: 1px solid transparent;
padding: .25em
}
.rw-cell:hover {
background-color: #e6e6e6;
border-color: #e6e6e6;
color: #333
}
.rw-cell.rw-state-focus,
.rw-cell.rw-state-focus:hover {
background-color: transparent;
color: #333
}
.rw-cell.rw-state-selected,
.rw-cell.rw-state-selected:hover {
background-color: #337ab7;
border-color: #337ab7;
color: white
}
.rw-cell.rw-state-disabled {
color: #999;
filter: alpha(opacity=7);
opacity: .7
}
.rw-cell.rw-state-disabled:hover {
background: none;
border-color: transparent
}
.rw-calendar-month .rw-cell {
text-align: center
}
.rw-cell-off-range {
color: #999
}
.rw-calendar-transition-group {
position: relative
}
.rw-calendar-transition {
transition: transform 300ms;
overflow: hidden
}
.rw-calendar-transition-top {
-ms-transform: translateY(-100%);
transform: translateY(-100%)
}
.rw-calendar-transition-bottom {
-ms-transform: translateY(100%);
transform: translateY(100%)
}
.rw-calendar-transition-right {
-ms-transform: translateX(-100%);
transform: translateX(-100%)
}
.rw-calendar-transition-left {
-ms-transform: translateX(100%);
transform: translateX(100%)
}
.rw-calendar-transition-entering.rw-calendar-transition-top,
.rw-calendar-transition-entered.rw-calendar-transition-top,
.rw-calendar-transition-entering.rw-calendar-transition-bottom,
.rw-calendar-transition-entered.rw-calendar-transition-bottom {
-ms-transform: translateY(0);
transform: translateY(0)
}
.rw-calendar-transition-entering.rw-calendar-transition-right,
.rw-calendar-transition-entered.rw-calendar-transition-right,
.rw-calendar-transition-entering.rw-calendar-transition-left,
.rw-calendar-transition-entered.rw-calendar-transition-left {
-ms-transform: translateX(0);
transform: translateX(0)
}
.rw-calendar-transition-exiting.rw-calendar-transition-top {
-ms-transform: translateY(100%);
transform: translateY(100%)
}
.rw-calendar-transition-exiting.rw-calendar-transition-bottom {
-ms-transform: translateY(-100%);
transform: translateY(-100%)
}
.rw-calendar-transition-exiting.rw-calendar-transition-right {
-ms-transform: translateX(100%);
transform: translateX(100%)
}
.rw-calendar-transition-exiting.rw-calendar-transition-left {
-ms-transform: translateX(-100%);
transform: translateX(-100%)
}
.rw-select-list {
overflow: auto;
position: relative
}
.rw-select-list .rw-list {
max-height: none;
font-size: 1em
}
.rw-select-list-label {
display: block;
position: relative;
font-weight: normal;
cursor: inherit;
padding-left: 20px;
margin: 0
}
.rw-rtl .rw-select-list-label {
padding-left: 0;
padding-right: 20px
}
input.rw-select-list-input {
position: absolute;
left: 0;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
top: 0.1em /9;
margin: 0;
line-height: normal;
cursor: inherit
}
.rw-rtl input.rw-select-list-input {
left: auto;
right: 0
}
.rw-loading-mask {
content: '';
background: url("../img/loader-big.gif") no-repeat center;
position: absolute;
background-color: #fff;
border-radius: 4px;
opacity: .7;
filter: alpha(opacity=70);
top: 0;
left: 0;
height: 100%;
width: 100%
}
.rw-multiselect {
cursor: text
}
.rw-multiselect .rw-input-reset {
height: calc(2.429em - 2px);
margin-top: -2px\9;
height: 2.429em\9;
border-width: 0;
width: auto;
max-width: 100%;
padding: 0 .857em
}
.rw-multiselect .rw-select,
.rw-multiselect .rw-select:hover,
.rw-multiselect .rw-select:active {
box-shadow: none;
background: none
}
.rw-multiselect-taglist {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
vertical-align: 0;
outline: none
}
.rw-multiselect-tag {
display: inline-table;
color: white;
font-weight: 500;
padding: 0 .35em 0 .35em;
margin-left: calc(0.279335em - 1px);
margin-top: .279335em;
margin-top: calc(0.279335em - 1px);
margin-bottom: calc(0.279335em + 2px);
height: 1.87033em;
border-radius: 4px;
background-color: #2598bc;
cursor: default;
vertical-align: top;
text-align: center;
overflow: hidden;
max-width: 100%
}
.rw-multiselect-tag>* {
display: table-cell;
vertical-align: middle;
height: 100%
}
.rw-rtl .rw-multiselect-tag {
margin-left: 0;
margin-right: calc(0.279335em - 1px);
padding: 0 .35em 0 .35em
}
.rw-multiselect-tag.rw-state-focus,
.rw-multiselect-tag.rw-state-focus:hover {
background-color: transparent;
color: #333
}
.rw-multiselect-tag.rw-state-readonly,
.rw-multiselect-tag.rw-state-disabled,
.rw-state-readonly .rw-multiselect-tag,
.rw-state-disabled .rw-multiselect-tag,
fieldset[disabled] .rw-multiselect-tag {
cursor: not-allowed
}
.rw-multiselect-tag.rw-state-disabled,
.rw-state-disabled .rw-multiselect-tag,
fieldset[disabled] .rw-multiselect-tag {
opacity: .65;
filter: alpha(opacity=65)
}
fieldset[disabled] .rw-multiselect-tag {
box-shadow: none;
cursor: not-allowed
}
.rw-multiselect-tag-btn {
color: inherit;
margin-left: .25em
}
.rw-rtl .rw-multiselect-tag-btn {
margin-left: 0;
margin-right: .25em
}
.rw-autocomplete .rw-select {
position: absolute;
display: block;
width: auto;
top: 0;
bottom: 0;
right: 0
}
.rw-popup-container {
position: absolute;
z-index: 1005;
top: 100%;
left: -6px;
right: -6px
}
.rw-popup-container.rw-dropup {
top: auto;
bottom: 100%
}
.rw-state-focus .rw-popup-container {
z-index: 1006
}
.rw-popup-transition {
width: 100%;
margin-bottom: 6px;
padding: 0 6px
}
.rw-dropup>.rw-popup-transition {
margin-bottom: 0;
margin-top: 6px
}
.rw-popup {
border-top-right-radius: 0;
border-top-left-radius: 0;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
box-shadow: 0 5px 6px rgba(0, 0, 0, 0.2);
border: #ccc 1px solid;
background: #fff
}
.rw-dropup .rw-popup {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.2)
}
.rw-popup-transition {
transition: transform 200ms
}
.rw-popup-transition-entering {
overflow: hidden
}
.rw-popup-transition-entering .rw-popup-transition {
-ms-transform: translateY(0);
transform: translateY(0);
transition-timing-function: ease-out
}
.rw-popup-transition-exiting .rw-popup-transition {
transition-timing-function: ease-in
}
.rw-popup-transition-exiting,
.rw-popup-transition-exited {
overflow: hidden
}
.rw-popup-transition-exiting .rw-popup-transition,
.rw-popup-transition-exited .rw-popup-transition {
-ms-transform: translateY(-100%);
transform: translateY(-100%)
}
.rw-popup-transition-exiting.rw-dropup .rw-popup-transition,
.rw-popup-transition-exited.rw-dropup .rw-popup-transition {
-ms-transform: translateY(100%);
transform: translateY(100%)
}
.rw-popup-transition-exited {
display: none
}
.rw-state-disabled {
box-shadow: none;
cursor: not-allowed
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,207 @@
.Tutorial-one {
padding: 10px;
background-image: url('../img/tutorials/1.png');
}
.Info-icon {
padding: 10px;
height: 50px;
width: 50px;
background-image: url('../img/tutorials/info.png');
}
.Tutorial-image--box {
height: 220px;
width: 520px;
padding: 10px;
}
.tut-Hide--check{
display: none;
}
#slider {
height: 35vw;
position: relative;
perspective: 1000px;
transform-style: preserve-3d;
}
#slider label {
margin: auto;
width: 60%;
height: 100%;
border-radius: 4px;
position: absolute;
left: 0;
right: 0;
cursor: pointer;
transition: transform 0.4s ease;
}
#s1:checked ~ #slide4,
#s2:checked ~ #slide5,
#s3:checked ~ #slide1,
#s4:checked ~ #slide2,
#s5:checked ~ #slide3 {
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .37);
transform: translate3d(-30%, 0, -200px);
}
#s1:checked~#slide5,
#s2:checked~#slide1,
#s3:checked~#slide2,
#s4:checked~#slide3,
#s5:checked~#slide4 {
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, .3), 0 2px 2px 0 rgba(0, 0, 0, .2);
transform: translate3d(-15%, 0, -100px);
}
#s1:checked~#slide1,
#s2:checked~#slide2,
#s3:checked~#slide3,
#s4:checked~#slide4,
#s5:checked~#slide5 {
box-shadow: 0 13px 25px 0 rgba(0, 0, 0, .3), 0 11px 7px 0 rgba(0, 0, 0, .19);
transform: translate3d(0, 0, 0);
}
#s1:checked~#slide2,
#s2:checked~#slide3,
#s3:checked~#slide4,
#s4:checked~#slide5,
#s5:checked~#slide1 {
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, .3), 0 2px 2px 0 rgba(0, 0, 0, .2);
transform: translate3d(15%, 0, -100px);
}
#s1:checked~#slide3,
#s2:checked~#slide4,
#s3:checked~#slide5,
#s4:checked~#slide1,
#s5:checked~#slide2 {
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .37);
transform: translate3d(30%, 0, -200px);
}
#slide1 {
background: #00BCD4;
}
#slide2 {
background: #4CAF50;
}
#slide3 {
background: #CDDC39;
}
#slide4 {
background: #FFC107;
}
#slide5 {
background: #FF5722
}
.tut-Icon--alarm {
content: url('../img/tutorials/alarm.png');
}
.tut-Icon--bell {
content: url('../img/tutorials/bell.png');
}
.tut-Icon--sol {
content: url('../img/tutorials/bulb.png');
}
.tut-Icon--info {
content: url('../img/tutorials/info.png');
}
.tut-Monitor--ack {
margin: 5px;
object-fit: fill;
object-position: center;
content: url('../img/tutorials/ack_rsv.png');
}
.tut-Monitor--metrics {
margin: 5px;
object-fit: fill;
object-position: center;
content: url('../img/tutorials/metrics.png');
}
.tut-Monitor--range {
margin: 5px;
object-fit: fill;
object-position: center;
content: url('../img/tutorials/range.png');
}
.tut-Monitor--incident {
margin: 5px;
object-fit: fill;
object-position: center;
content: url('../img/tutorials/incidents.png');
}
.tut-Monitor--monitor {
margin: 5px;
object-fit: fill;
object-position: center;
content: url('../img/tutorials/monitor.png');
}
.bs-Button--icon--right.bs-Button--eye:after,
.bs-Button--eye:before {
padding-top: 2px;
size: 7px;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA20lEQVQ4T+3SP0tCURgH4MchCITCVcIhaGoRRPADuPQJkiAo55YGJ50cHAUXNzFaCpzc/QKBg3NjRHOBTi1x4SAi1+4FHRw8cJbz53l5f7wZO16ZHXsO4PaJps0wG0otkkr+B57hHlWcBugHEwzwFYdvAuu4RQdzvITP1zhBC08YrqNx4DNm6OIIr/gOu4Ab/KKBS9ytonFgDVfo4w29AEftHuMRFTxgjFESGN2fo41PRFApfJoihzya+EjT8uqbMoq4CIfvIY4Ijl1pxyZpWpb3BzB1VBsf7n+Gf+YPHxVDqgqmAAAAAElFTkSuQmCC');
}
.bs-Button--icon--right.bs-Button--eye:active:after,
.bs-Button--icon--right.bs-Button--eye:focus:hover:after,
.bs-Button--icon--right.bs-Button--eye:hover:after,
.bs-Button--eye:active:before,
.bs-Button--eye:focus:hover:before,
.bs-Button--eye:hover:before {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA20lEQVQ4T+3SP0tCURgH4MchCITCVcIhaGoRRPADuPQJkiAo55YGJ50cHAUXNzFaCpzc/QKBg3NjRHOBTi1x4SAi1+4FHRw8cJbz53l5f7wZO16ZHXsO4PaJps0wG0otkkr+B57hHlWcBugHEwzwFYdvAuu4RQdzvITP1zhBC08YrqNx4DNm6OIIr/gOu4Ab/KKBS9ytonFgDVfo4w29AEftHuMRFTxgjFESGN2fo41PRFApfJoihzya+EjT8uqbMoq4CIfvIY4Ijl1pxyZpWpb3BzB1VBsf7n+Gf+YPHxVDqgqmAAAAAElFTkSuQmCC');
}
.bs-Button--blue.bs-Button--eye:before,
.bs-Button--blue.bs-Button--eye:hover:before,
.bs-Button--icon--right.bs-Button--blue.bs-Button--eye:after,
.bs-Button--icon--right.bs-Button--blue.bs-Button--eye:hover:after,
.bs-Button--icon--right.bs-Button--eye.bs-Button--blue.bs-is-disabled:after,
.bs-Button--icon--right.bs-Button--eye.bs-Button--blue:disabled:after,
.bs-Button--eye.bs-Button--blue.bs-is-disabled:before,
.bs-Button--eye.bs-Button--blue:disabled:before {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA20lEQVQ4T+3SP0tCURgH4MchCITCVcIhaGoRRPADuPQJkiAo55YGJ50cHAUXNzFaCpzc/QKBg3NjRHOBTi1x4SAi1+4FHRw8cJbz53l5f7wZO16ZHXsO4PaJps0wG0otkkr+B57hHlWcBugHEwzwFYdvAuu4RQdzvITP1zhBC08YrqNx4DNm6OIIr/gOu4Ab/KKBS9ytonFgDVfo4w29AEftHuMRFTxgjFESGN2fo41PRFApfJoihzya+EjT8uqbMoq4CIfvIY4Ijl1pxyZpWpb3BzB1VBsf7n+Gf+YPHxVDqgqmAAAAAElFTkSuQmCC');
}
.bs-Button--icon--right.bs-Button--link.bs-Button--eye:after,
.bs-Button--link.bs-Button--eye:before {
height: 10px;
width: 15px;
height: 15px;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA20lEQVQ4T+3SP0tCURgH4MchCITCVcIhaGoRRPADuPQJkiAo55YGJ50cHAUXNzFaCpzc/QKBg3NjRHOBTi1x4SAi1+4FHRw8cJbz53l5f7wZO16ZHXsO4PaJps0wG0otkkr+B57hHlWcBugHEwzwFYdvAuu4RQdzvITP1zhBC08YrqNx4DNm6OIIr/gOu4Ab/KKBS9ytonFgDVfo4w29AEftHuMRFTxgjFESGN2fo41PRFApfJoihzya+EjT8uqbMoq4CIfvIY4Ijl1pxyZpWpb3BzB1VBsf7n+Gf+YPHxVDqgqmAAAAAElFTkSuQmCC');
}
.bs-Button--icon--right.bs-Button--link.bs-Button--eye:active:after,
.bs-Button--icon--right.bs-Button--link.bs-Button--eye:hover:after,
.bs-Button--link.bs-Button--eye:active:before,
.bs-Button--link.bs-Button--eye:hover:before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+c2V0dGluZ3MtLWhvdmVyPC90aXRsZT48cGF0aCBkPSJNMTQuNDI2IDkuMjk4Yy0uMTY0IDAtMS4xNDcgMC0xLjU1Ny0uNDk2IDAtLjA4My0uMDgyLS4wODMtLjA4Mi0uMTY2LS4wODItLjU3OC42NTYtMS4zMjIuNzM4LTEuNDA1LjE2NC0uMTY1LjE2NC0uNDEzLjA4Mi0uNDk1LS4wODItLjA4My0uNDEtLjQxNC0uNDkyLS41NzktLjA4Mi0uMTY1LS4zMjgtLjA4My0uNDkyLjA4My0uMTY0LjE2NS0uODIuODI2LTEuMzkzLjc0My0uMDgyIDAtLjA4Mi0uMDgyLS4xNjQtLjA4Mi0uNDkyLS4zMy0uNDkyLTEuMzIyLS40OTItMS40ODggMC0uMjQ4LS4wODItLjQxMy0uMjQ2LS40MTNoLS44MmMtLjE2NCAwLS4yNDYuMTY1LS4yNDYuNDEzIDAgLjE2NiAwIDEuMTU3LS40OTIgMS41Ny0uMDgxIDAtLjA4MS4wODMtLjE2My4wODMtLjU3NCAwLTEuMjMtLjY2MS0xLjM5NC0uODI2LS4xNjQtLjE2Ni0uNDEtLjE2Ni0uNDkyLS4wODMtLjA4Mi4xNjUtLjQxLjQ5Ni0uNTczLjU3OS0uMDgyLjA4Mi0uMDgyLjMzLjA4Mi40OTUuMTYzLjE2Ni44Mi44MjcuNzM3IDEuNDA1IDAgLjA4My0uMDgyLjA4My0uMDgyLjE2Ni0uMzI4LjQ5Ni0xLjMxMS40OTYtMS40NzUuNDk2LS4yNDYgMC0uNDEuMDgyLS40MS4yNDd2Ljc0NGMwIC4xNjYuMTY0LjMzLjQxLjMzLjE2NCAwIDEuMTQ3IDAgMS41NTcuNDk3IDAgLjA4Mi4wODIuMDgyLjA4Mi4xNjUuMDgyLjU3OS0uNjU2IDEuMzIyLS43MzggMS40MDUtLjE2My4xNjUtLjE2My40MTMtLjA4MS40OTYuMDgxLjA4Mi40MS40MTMuNDkxLjU3OC4wODIuMDgzLjMyOC4wODMuNDkyLS4wODIuMTY0LS4xNjYuODItLjgyNyAxLjM5NC0uNzQ0LjA4MiAwIC4wODIuMDgzLjE2My4wODMuNDkyLjQxMy40OTIgMS4zMjIuNDkyIDEuNTcgMCAuMTY1LjE2NC40MTMuMzI4LjQxM2guNzM4Yy4xNjQgMCAuMzI4LS4xNjUuMzI4LS40MTMgMC0uMTY2IDAtMS4xNTcuNDkyLTEuNTcuMDgyIDAgLjA4Mi0uMDgzLjE2My0uMDgzLjU3NC0uMDgzIDEuMzEyLjY2MSAxLjM5NC43NDQuMTY0LjE2NS40MS4xNjUuNDkyLjA4MmwuNTczLS41NzhjLjA4Mi0uMDgzLjA4Mi0uMzMtLjA4MS0uNDk2LS4xNjQtLjE2NS0uODItLjgyNi0uNzM4LTEuNDA1IDAtLjA4My4wODItLjA4My4wODItLjE2NS40MS0uNDk2IDEuMzExLS40OTYgMS41NTctLjQ5Ni4xNjQgMCAuNDEtLjE2NS40MS0uMzN2LS43NDVhLjc0MS43NDEgMCAwIDAtLjU3NC0uMjQ3ek0xMCAxMi4wMzNjLTEuMDkgMC0yLS45MTctMi0yLjAxNkM4IDguOTE3IDguOTEgOCAxMCA4YzEuMDkgMCAyIC45MTcgMiAyLjAxNyAwIDEuMS0uOTEgMi4wMTYtMiAyLjAxNnoiIGZpbGw9IiMzMjMyNUQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==');
}
.bs-Button--icon--right.bs-Button--eye.bs-is-disabled:after,
.bs-Button--icon--right.bs-Button--eye:disabled:after,
.bs-Button--link.bs-Button--icon--right.bs-Button--eye.bs-is-disabled:after,
.bs-Button--link.bs-Button--icon--right.bs-Button--eye:disabled:after,
.bs-Button--link.bs-Button--eye.bs-is-disabled:before,
.bs-Button--link.bs-Button--eye:disabled:before,
.bs-Button--eye.bs-is-disabled:before,
.bs-Button--eye:disabled:before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+c2V0dGluZ3MtLWRpc2FibGVkPC90aXRsZT48cGF0aCBkPSJNMTQuNDI2IDkuMjk4Yy0uMTY0IDAtMS4xNDcgMC0xLjU1Ny0uNDk2IDAtLjA4My0uMDgyLS4wODMtLjA4Mi0uMTY2LS4wODItLjU3OC42NTYtMS4zMjIuNzM4LTEuNDA1LjE2NC0uMTY1LjE2NC0uNDEzLjA4Mi0uNDk1LS4wODItLjA4My0uNDEtLjQxNC0uNDkyLS41NzktLjA4Mi0uMTY1LS4zMjgtLjA4My0uNDkyLjA4My0uMTY0LjE2NS0uODIuODI2LTEuMzkzLjc0My0uMDgyIDAtLjA4Mi0uMDgyLS4xNjQtLjA4Mi0uNDkyLS4zMy0uNDkyLTEuMzIyLS40OTItMS40ODggMC0uMjQ4LS4wODItLjQxMy0uMjQ2LS40MTNoLS44MmMtLjE2NCAwLS4yNDYuMTY1LS4yNDYuNDEzIDAgLjE2NiAwIDEuMTU3LS40OTIgMS41Ny0uMDgxIDAtLjA4MS4wODMtLjE2My4wODMtLjU3NCAwLTEuMjMtLjY2MS0xLjM5NC0uODI2LS4xNjQtLjE2Ni0uNDEtLjE2Ni0uNDkyLS4wODMtLjA4Mi4xNjUtLjQxLjQ5Ni0uNTczLjU3OS0uMDgyLjA4Mi0uMDgyLjMzLjA4Mi40OTUuMTYzLjE2Ni44Mi44MjcuNzM3IDEuNDA1IDAgLjA4My0uMDgyLjA4My0uMDgyLjE2Ni0uMzI4LjQ5Ni0xLjMxMS40OTYtMS40NzUuNDk2LS4yNDYgMC0uNDEuMDgyLS40MS4yNDd2Ljc0NGMwIC4xNjYuMTY0LjMzLjQxLjMzLjE2NCAwIDEuMTQ3IDAgMS41NTcuNDk3IDAgLjA4Mi4wODIuMDgyLjA4Mi4xNjUuMDgyLjU3OS0uNjU2IDEuMzIyLS43MzggMS40MDUtLjE2My4xNjUtLjE2My40MTMtLjA4MS40OTYuMDgxLjA4Mi40MS40MTMuNDkxLjU3OC4wODIuMDgzLjMyOC4wODMuNDkyLS4wODIuMTY0LS4xNjYuODItLjgyNyAxLjM5NC0uNzQ0LjA4MiAwIC4wODIuMDgzLjE2My4wODMuNDkyLjQxMy40OTIgMS4zMjIuNDkyIDEuNTcgMCAuMTY1LjE2NC40MTMuMzI4LjQxM2guNzM4Yy4xNjQgMCAuMzI4LS4xNjUuMzI4LS40MTMgMC0uMTY2IDAtMS4xNTcuNDkyLTEuNTcuMDgyIDAgLjA4Mi0uMDgzLjE2My0uMDgzLjU3NC0uMDgzIDEuMzEyLjY2MSAxLjM5NC43NDQuMTY0LjE2NS40MS4xNjUuNDkyLjA4MmwuNTczLS41NzhjLjA4Mi0uMDgzLjA4Mi0uMzMtLjA4MS0uNDk2LS4xNjQtLjE2NS0uODItLjgyNi0uNzM4LTEuNDA1IDAtLjA4My4wODItLjA4My4wODItLjE2NS40MS0uNDk2IDEuMzExLS40OTYgMS41NTctLjQ5Ni4xNjQgMCAuNDEtLjE2NS40MS0uMzN2LS43NDVhLjc0MS43NDEgMCAwIDAtLjU3NC0uMjQ3ek0xMCAxMi4wMzNjLTEuMDkgMC0yLS45MTctMi0yLjAxNkM4IDguOTE3IDguOTEgOCAxMCA4YzEuMDkgMCAyIC45MTcgMiAyLjAxNyAwIDEuMS0uOTEgMi4wMTYtMiAyLjAxNnoiIGZpbGw9IiM4ODk4QUEiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,24 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2017 by original authors @ fontello.com</metadata>
<defs>
<font id="rw-widgets" horiz-adv-x="1000" >
<font-face font-family="rw-widgets" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="up-dir" unicode="&#xe800;" d="M571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
<glyph glyph-name="search" unicode="&#xe801;" d="M643 386q0 103-73 176t-177 74-177-74-73-176 73-177 177-73 177 73 73 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 153-31 125-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
<glyph glyph-name="down-dir" unicode="&#xe803;" d="M571 457q0-14-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25t11 25 25 11h500q14 0 25-11t10-25z" horiz-adv-x="571.4" />
<glyph glyph-name="calendar" unicode="&#xe804;" d="M71-79h161v161h-161v-161z m197 0h178v161h-178v-161z m-197 197h161v178h-161v-178z m197 0h178v178h-178v-178z m-197 214h161v161h-161v-161z m411-411h179v161h-179v-161z m-214 411h178v161h-178v-161z m428-411h161v161h-161v-161z m-214 197h179v178h-179v-178z m-196 482v161q0 7-6 12t-12 6h-36q-7 0-12-6t-6-12v-161q0-7 6-13t12-5h36q7 0 12 5t6 13z m410-482h161v178h-161v-178z m-214 214h179v161h-179v-161z m214 0h161v161h-161v-161z m18 268v161q0 7-5 12t-13 6h-35q-7 0-13-6t-5-12v-161q0-7 5-13t13-5h35q8 0 13 5t5 13z m215 36v-715q0-29-22-50t-50-21h-786q-29 0-50 21t-21 50v715q0 29 21 50t50 21h72v54q0 37 26 63t63 26h36q37 0 63-26t26-63v-54h214v54q0 37 27 63t63 26h35q37 0 64-26t26-63v-54h71q29 0 50-21t22-50z" horiz-adv-x="928.6" />
<glyph glyph-name="clock" unicode="&#xe805;" d="M500 546v-250q0-7-5-12t-13-5h-178q-8 0-13 5t-5 12v36q0 8 5 13t13 5h125v196q0 8 5 13t12 5h36q8 0 13-5t5-13z m232-196q0 83-41 152t-110 111-152 41-153-41-110-111-41-152 41-152 110-111 153-41 152 41 110 111 41 152z m125 0q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="angle-left" unicode="&#xf104;" d="M350 546q0-7-6-12l-219-220 219-219q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-260 261q-6 5-6 12t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="357.1" />
<glyph glyph-name="angle-right" unicode="&#xf105;" d="M332 314q0-7-5-12l-261-261q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l261-260q5-5 5-13z" horiz-adv-x="357.1" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 52 52" style="enable-background:new 0 0 52 52;" xml:space="preserve" width="512px" height="512px" class=""><g><g>
<path d="M26,0C11.664,0,0,11.663,0,26s11.664,26,26,26s26-11.663,26-26S40.336,0,26,0z M40.495,17.329l-16,18 C24.101,35.772,23.552,36,22.999,36c-0.439,0-0.88-0.144-1.249-0.438l-10-8c-0.862-0.689-1.002-1.948-0.312-2.811 c0.689-0.863,1.949-1.003,2.811-0.313l8.517,6.813l14.739-16.581c0.732-0.826,1.998-0.9,2.823-0.166 C41.154,15.239,41.229,16.503,40.495,17.329z" data-original="#000000" class="active-path" data-old_color="#FFE000" fill="#FFEF00"/>
</g></g> </svg>

After

Width:  |  Height:  |  Size: 742 B

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="566.38" height="275.072" viewBox="0 0 566.38 275.07" enable-background="new 0 0 566.38 275.07" xml:space="preserve">
<rect x="0" y="3.05176e-005" fill="#FFFFFF" fill-opacity="0" stroke-width="0.2" stroke-linejoin="round" width="566.38" height="275.072"/>
<g>
<path fill="#32325D" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 219.416,91.5147C 217.198,90.5867 214.668,90.1228 211.826,90.1228C 203.852,90.1228 199.865,94.4217 199.865,103.019L 199.865,112.393L 216.632,112.393L 216.632,124.919L 199.93,124.919L 199.93,181.986L 184.619,181.986L 184.619,124.919L 172.093,124.919L 172.093,112.393L 184.619,112.393L 184.619,101.171C 184.619,93.878 187.044,88.1256 191.894,83.9138C 196.744,79.7019 202.808,77.596 210.086,77.596C 214.015,77.596 217.125,78.0092 219.416,78.8356L 219.416,91.5147 Z "/>
<path fill="#32325D" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 291.097,112.393L 259.324,193.252C 252.669,208.011 243.339,215.391 231.334,215.391C 227.97,215.391 225.158,215.101 222.896,214.521L 222.896,201.472C 225.448,202.4 227.76,202.864 229.833,202.864C 235.85,202.864 240.345,199.856 243.317,193.839L 248.102,181.986L 220.112,112.393L 237.576,112.393L 254.539,163.065C 254.728,163.703 255.148,165.385 255.8,168.111L 256.148,168.111C 256.38,167.067 256.794,165.429 257.388,163.196L 275.2,112.393L 291.097,112.393 Z "/>
<rect x="300.84" y="112.393" fill="#32325D" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" width="15.3105" height="69.5934"/>
<path fill="#32325D" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 352.622,171.46L 352.34,171.46L 352.34,213.999L 337.029,213.999L 337.029,112.393L 352.34,112.393L 352.34,124.811L 352.622,124.811C 358.103,115.604 366.121,111.001 376.676,111.001C 385.665,111.001 392.671,114.093 397.695,120.276C 402.719,126.46 405.231,134.764 405.231,145.189C 405.231,156.744 402.396,165.998 396.727,172.95C 391.058,179.902 383.316,183.378 373.5,183.378C 364.468,183.378 357.508,179.405 352.622,171.46 Z M 352.209,144.253L 352.209,152.8C 352.209,157.831 353.844,162.098 357.113,165.599C 360.383,169.1 364.54,170.851 369.586,170.851C 375.487,170.851 380.119,168.597 383.483,164.088C 386.846,159.579 388.528,153.286 388.528,145.21C 388.528,138.425 386.962,133.115 383.831,129.28C 380.699,125.445 376.451,123.528 371.086,123.528C 365.417,123.528 360.854,125.503 357.396,129.454C 353.938,133.405 352.209,138.338 352.209,144.253 Z "/>
<path fill="#32325D" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 481.784,151.365L 433.068,151.365C 433.257,157.599 435.294,162.406 439.179,165.784C 443.065,169.162 448.408,170.851 455.207,170.851C 462.834,170.851 469.837,168.531 476.216,163.892L 476.216,177.136C 469.663,181.297 461.007,183.378 450.249,183.378C 439.679,183.378 431.39,180.239 425.38,173.961C 419.37,167.683 416.366,158.846 416.366,147.45C 416.366,136.692 419.671,127.928 426.283,121.157C 432.894,114.386 441.108,111.001 450.923,111.001C 460.739,111.001 468.336,114.035 473.715,120.102C 479.094,126.17 481.784,134.59 481.784,145.363L 481.784,151.365 Z M 465.081,140.23C 465.038,134.953 463.711,130.849 461.101,127.921C 458.491,124.992 454.888,123.528 450.292,123.528C 445.783,123.528 441.967,125.068 438.842,128.149C 435.718,131.23 433.793,135.257 433.068,140.23L 465.081,140.23 Z "/>
</g>
<path fill="#6CDB56" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 138.368,85.8314L 152.867,85.8314C 155.076,85.8314 156.867,87.6222 156.867,89.8314L 156.867,177.826C 156.867,180.036 155.076,181.826 152.867,181.826L 138.368,181.826C 136.159,181.826 134.368,180.036 134.368,177.826L 134.368,89.8314C 134.368,87.6222 136.159,85.8314 138.368,85.8314 Z "/>
<path fill="#6CDB56" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 106.62,86.581L 121.119,86.581C 123.328,86.581 125.119,88.3719 125.119,90.581L 125.119,178.576C 125.119,180.785 123.328,182.576 121.119,182.576L 106.62,182.576C 104.411,182.576 102.62,180.785 102.62,178.576L 102.62,90.581C 102.62,88.3719 104.411,86.581 106.62,86.581 Z "/>
<path fill="#6CDB56" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 74.1223,86.0808L 88.6212,86.0808C 90.8303,86.0808 92.6212,87.8717 92.6212,90.0808L 92.6212,178.076C 92.6212,180.285 90.8303,182.076 88.6212,182.076L 74.1223,182.076C 71.9131,182.076 70.1223,180.285 70.1223,178.076L 70.1223,90.0808C 70.1223,87.8717 71.9131,86.0808 74.1223,86.0808 Z "/>
</svg>

View File

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 212.982 212.982" style="enable-background:new 0 0 212.982 212.982;" xml:space="preserve" width="512px" height="512px" class=""><g><g id="Close">
<path d="M131.804,106.491l75.936-75.936c6.99-6.99,6.99-18.323,0-25.312 c-6.99-6.99-18.322-6.99-25.312,0l-75.937,75.937L30.554,5.242c-6.99-6.99-18.322-6.99-25.312,0c-6.989,6.99-6.989,18.323,0,25.312 l75.937,75.936L5.242,182.427c-6.989,6.99-6.989,18.323,0,25.312c6.99,6.99,18.322,6.99,25.312,0l75.937-75.937l75.937,75.937 c6.989,6.99,18.322,6.99,25.312,0c6.99-6.99,6.99-18.322,0-25.312L131.804,106.491z" data-original="#000000" class="active-path" data-old_color="#6b7c93" fill="#6b7c93"/>
</g></g> </svg>

After

Width:  |  Height:  |  Size: 816 B

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="612px" height="612px" viewBox="0 0 612 612" style="enable-background:new 0 0 612 612;" xml:space="preserve">
<g>
<g id="Check">
<g>
<path d="M306,0C137.012,0,0,137.012,0,306s137.012,306,306,306s306-137.012,306-306S474.988,0,306,0z M306,554.625
C168.912,554.625,57.375,443.088,57.375,306S168.912,57.375,306,57.375S554.625,168.912,554.625,306S443.088,554.625,306,554.625
z M431.46,210.604c-7.707-0.325-15.529,2.276-21.42,8.186L277.312,351.498l-75.353-75.333c-5.891-5.91-13.712-8.492-21.42-8.186
c-6.942,0.287-13.847,2.869-19.144,8.186c-5.298,5.298-7.899,12.202-8.186,19.144c-0.325,7.708,2.276,15.53,8.186,21.42
l95.625,95.625c5.604,5.604,12.948,8.396,20.292,8.396s14.688-2.792,20.292-8.396l153-153c5.909-5.91,8.491-13.712,8.186-21.42
c-0.287-6.942-2.869-13.846-8.186-19.144C445.287,213.473,438.402,210.872,431.46,210.604z"/>
</g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 55.25 55.25" style="enable-background:new 0 0 55.25 55.25;" xml:space="preserve">
<path d="M52.618,2.631c-3.51-3.508-9.219-3.508-12.729,0L3.827,38.693C3.81,38.71,3.8,38.731,3.785,38.749
c-0.021,0.024-0.039,0.05-0.058,0.076c-0.053,0.074-0.094,0.153-0.125,0.239c-0.009,0.026-0.022,0.049-0.029,0.075
c-0.003,0.01-0.009,0.02-0.012,0.03l-3.535,14.85c-0.016,0.067-0.02,0.135-0.022,0.202C0.004,54.234,0,54.246,0,54.259
c0.001,0.114,0.026,0.225,0.065,0.332c0.009,0.025,0.019,0.047,0.03,0.071c0.049,0.107,0.11,0.21,0.196,0.296
c0.095,0.095,0.207,0.168,0.328,0.218c0.121,0.05,0.25,0.075,0.379,0.075c0.077,0,0.155-0.009,0.231-0.027l14.85-3.535
c0.027-0.006,0.051-0.021,0.077-0.03c0.034-0.011,0.066-0.024,0.099-0.039c0.072-0.033,0.139-0.074,0.201-0.123
c0.024-0.019,0.049-0.033,0.072-0.054c0.008-0.008,0.018-0.012,0.026-0.02l36.063-36.063C56.127,11.85,56.127,6.14,52.618,2.631z
M51.204,4.045c2.488,2.489,2.7,6.397,0.65,9.137l-9.787-9.787C44.808,1.345,48.716,1.557,51.204,4.045z M46.254,18.895l-9.9-9.9
l1.414-1.414l9.9,9.9L46.254,18.895z M4.961,50.288c-0.391-0.391-1.023-0.391-1.414,0L2.79,51.045l2.554-10.728l4.422-0.491
l-0.569,5.122c-0.004,0.038,0.01,0.073,0.01,0.11c0,0.038-0.014,0.072-0.01,0.11c0.004,0.033,0.021,0.06,0.028,0.092
c0.012,0.058,0.029,0.111,0.05,0.165c0.026,0.065,0.057,0.124,0.095,0.181c0.031,0.046,0.062,0.087,0.1,0.127
c0.048,0.051,0.1,0.094,0.157,0.134c0.045,0.031,0.088,0.06,0.138,0.084C9.831,45.982,9.9,46,9.972,46.017
c0.038,0.009,0.069,0.03,0.108,0.035c0.036,0.004,0.072,0.006,0.109,0.006c0,0,0.001,0,0.001,0c0,0,0.001,0,0.001,0h0.001
c0,0,0.001,0,0.001,0c0.036,0,0.073-0.002,0.109-0.006l5.122-0.569l-0.491,4.422L4.204,52.459l0.757-0.757
C5.351,51.312,5.351,50.679,4.961,50.288z M17.511,44.809L39.889,22.43c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0
L16.097,43.395l-4.773,0.53l0.53-4.773l22.38-22.378c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0L10.44,37.738
l-3.183,0.354L34.94,10.409l9.9,9.9L17.157,47.992L17.511,44.809z M49.082,16.067l-9.9-9.9l1.415-1.415l9.9,9.9L49.082,16.067z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56.061px" height="56.062px" viewBox="0 0 56.061 56.062" style="enable-background:new 0 0 56.061 56.062;"
xml:space="preserve">
<g>
<g>
<path d="M40.149,12.335H15.914c-2.02,0-3.661,1.653-3.661,3.694l1.653,36.37c0,2.021,1.644,3.662,3.662,3.662h20.926
c2.021,0,3.662-1.632,3.662-3.63l1.653-36.436C43.811,13.979,42.166,12.335,40.149,12.335z M38.492,52.447l-20.971-0.078
l-1.654-36.372c0-0.024,0.021-0.046,0.047-0.046l24.28,0.014L38.492,52.447z"/>
<path d="M28.05,50.393c1.069,0,1.94-0.87,1.94-1.939V22.23c0-1.068-0.869-1.938-1.94-1.938c-1.068,0-1.938,0.87-1.938,1.938
v26.223C26.113,49.522,26.981,50.393,28.05,50.393z"/>
<path d="M35.069,50.392h0.02c1.059,0,1.93-0.859,1.941-1.918l0.299-26.22c0.006-0.519-0.189-1.007-0.553-1.378
c-0.364-0.371-0.846-0.578-1.387-0.584c-1.06,0-1.929,0.859-1.939,1.917l-0.301,26.22C33.139,49.499,33.998,50.38,35.069,50.392z"
/>
<path d="M20.972,50.392h0.02c1.07-0.013,1.931-0.894,1.918-1.963l-0.299-26.22c-0.012-1.058-0.883-1.917-1.961-1.917
c-0.52,0.006-1.004,0.213-1.367,0.584c-0.362,0.371-0.557,0.859-0.551,1.378l0.299,26.22
C19.042,49.532,19.914,50.392,20.972,50.392z"/>
<path d="M14.707,10.91l27.086-1.562c0.468-0.026,0.896-0.233,1.209-0.585c0.312-0.35,0.47-0.8,0.438-1.266
c-0.053-0.929-0.819-1.653-1.75-1.653L14.604,7.406c-0.467,0.026-0.896,0.233-1.207,0.585c-0.312,0.35-0.471,0.8-0.44,1.267
C13.006,10.184,13.776,10.91,14.707,10.91z M14.707,10.396C14.707,10.396,14.707,10.397,14.707,10.396v0.014V10.396z"/>
<path d="M23.854,6.294l0.104-0.003c0.481-0.027,0.926-0.241,1.245-0.603c0.322-0.36,0.484-0.824,0.455-1.307l0.021-0.49
l4.833-0.232l0.025,0.44c0.057,0.956,0.848,1.704,1.803,1.704L32.446,5.8c0.482-0.028,0.926-0.242,1.246-0.603
c0.322-0.36,0.481-0.825,0.455-1.308l-0.025-0.439c-0.115-2.007-1.848-3.553-3.865-3.445L25.47,0.281
c-2.017,0.115-3.562,1.852-3.443,3.866l0.025,0.441C22.106,5.546,22.897,6.294,23.854,6.294z M23.854,5.783L23.854,5.783v0.013
V5.783z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M256,0C114.613,0,0,114.617,0,256c0,141.391,114.613,256,256,256s256-114.609,256-256C512,114.617,397.387,0,256,0z
M256,128c17.674,0,32,14.328,32,32c0,17.68-14.326,32-32,32s-32-14.32-32-32C224,142.328,238.326,128,256,128z M304,384h-96
c-8.836,0-16-7.156-16-16c0-8.836,7.164-16,16-16h16v-96h-16c-8.836,0-16-7.156-16-16c0-8.836,7.164-16,16-16h64
c8.836,0,16,7.164,16,16v112h16c8.836,0,16,7.164,16,16C320,376.844,312.836,384,304,384z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="512px" height="512px" class=""><g><path d="M256,0C114.613,0,0,114.617,0,256c0,141.391,114.613,256,256,256s256-114.609,256-256C512,114.617,397.387,0,256,0z M256,128c17.674,0,32,14.328,32,32c0,17.68-14.326,32-32,32s-32-14.32-32-32C224,142.328,238.326,128,256,128z M304,384h-96 c-8.836,0-16-7.156-16-16c0-8.836,7.164-16,16-16h16v-96h-16c-8.836,0-16-7.156-16-16c0-8.836,7.164-16,16-16h64 c8.836,0,16,7.164,16,16v112h16c8.836,0,16,7.164,16,16C320,376.844,312.836,384,304,384z" data-original="#000000" class="active-path" data-old_color="#14aad9" fill="#14aad9"/></g> </svg>

After

Width:  |  Height:  |  Size: 813 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 52 52" style="enable-background:new 0 0 52 52;" xml:space="preserve" width="512px" height="512px" class=""><g><g>
<path d="M26,0C11.664,0,0,11.663,0,26s11.664,26,26,26s26-11.663,26-26S40.336,0,26,0z M40.495,17.329l-16,18 C24.101,35.772,23.552,36,22.999,36c-0.439,0-0.88-0.144-1.249-0.438l-10-8c-0.862-0.689-1.002-1.948-0.312-2.811 c0.689-0.863,1.949-1.003,2.811-0.313l8.517,6.813l14.739-16.581c0.732-0.826,1.998-0.9,2.823-0.166 C41.154,15.239,41.229,16.503,40.495,17.329z" data-original="#000000" class="active-path" data-old_color="#00FF33" fill="#00FF2B"/>
</g></g> </svg>

After

Width:  |  Height:  |  Size: 742 B

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="459px" height="459px" viewBox="0 0 459 459" style="enable-background:new 0 0 459 459;" xml:space="preserve">
<g>
<g id="unfold-more">
<path d="M229.5,71.4l81.6,81.6l35.7-35.7L229.5,0L112.2,117.3l35.7,35.7L229.5,71.4z M229.5,387.6L147.9,306l-35.7,35.7L229.5,459
l117.3-117.3L311.1,306L229.5,387.6z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 831 B

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<circle style="fill:#25AE88;" cx="25" cy="25" r="25"/>
<polyline style="fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
38,15 22,33 12,25 "/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<circle style="fill:#EFCE4A;" cx="25" cy="25" r="25"/>
<line style="fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;" x1="25" y1="10" x2="25" y2="32"/>
<line style="fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;" x1="25" y1="37" x2="25" y2="39"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 808 B

View File

@ -0,0 +1,9 @@
$(document).ready(function() {
setTimeout(()=>{
$('div.bar').tipsy({
gravity: 'se',
html: true,
offset: 1
});
},1000);
});

BIN
accounts/public/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

91
accounts/public/index.html Executable file
View File

@ -0,0 +1,91 @@
<!doctype html>
<html lang="">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charSet='utf-8' />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta name="slack-app-id" content="ACVBMTPJQ">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<title>Fyipe Dashboard</title>
<link rel="stylesheet" href="/assets/css/dashboard.css">
<link rel="stylesheet" href="/assets/css/newdashboard.css">
<link rel="stylesheet" href="/assets/css/sail.css">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="stylesheet" href="/assets/css/loader.css">
<link rel="stylesheet" href="/assets/css/blockchart.css">
<link rel="stylesheet" href="/assets/css/Selector.css">
<link rel="stylesheet" href="/assets/css/tutorial.css">
<link rel="stylesheet" href="/assets/css/reactwidgets.css">
<!-- Preload light, regular, medium and bold, which are fonts that are used on home -->
<link rel="preload" href="/assets/fonts/camphor/font1.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="preload" href="/assets/fonts/camphor/font2.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="preload" href="/assets/fonts/camphor/font3.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="preload" href="/assets/fonts/camphor/font4.woff2" as="font" type="font/woff2" crossorigin="">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.3/jquery.tipsy.min.js" type="text/javascript"></script>
<style type="text/css">
/* Camphor */
@font-face {
font-family: 'Camphor';
font-weight: 300;
src: url('/assets/fonts/camphor/font1.woff2') format('woff2'),
url('/assets/fonts/camphor/font1.woff') format('woff');
}
@font-face {
font-family: 'Camphor';
font-weight: 500;
src: url('/assets/fonts/camphor/font2.woff2') format('woff2'),
url('/assets/fonts/camphor/font2.woff') format('woff');
}
@font-face {
font-family: 'Camphor';
font-weight: 600;
src: url('/assets/fonts/camphor/font3.woff2') format('woff2'),
url('/assets/fonts/camphor/font3.woff') format('woff');
}
@font-face {
font-family: 'Camphor';
font-weight: 400;
src: url('/assets/fonts/camphor/font4.woff2') format('woff2'),
url('/assets/fonts/camphor/font4.woff') format('woff');
}
</style>
<!-- Google Tag Manager -->
<script>(function (w, d, s, l, i) {
w[l] = w[l] || []; w[l].push({
'gtm.start':
new Date().getTime(), event: 'gtm.js'
}); var f = d.getElementsByTagName(s)[0],
j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-PKQD5WH');</script>
<!-- End Google Tag Manager -->
</head>
<body>
<div id="root" class="db-DashboardRoot"></div>
<script>
!function () {
if ('PerformanceLongTaskTiming' in window) {
var g = window.__tti = { e: [] };
g.o = new PerformanceObserver(function (l) { g.e = g.e.concat(l.getEntries()) });
g.o.observe({ entryTypes: ['longtask'] })
}
}();
</script>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PKQD5WH" height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
</body>
</html>

15
accounts/public/manifest.json Executable file
View File

@ -0,0 +1,15 @@
{
"short_name": "Fyipe",
"name": "Fyipe Dashboard",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

51
accounts/src/App.js Executable file
View File

@ -0,0 +1,51 @@
import React from 'react';
import { Router, Route, Redirect, Switch } from 'react-router-dom';
import { history, isServer } from './store';
import { connect } from 'react-redux';
import { allRoutes } from './routes';
import NotFound from './components/404';
import BackboneModals from './containers/BackboneModals';
import ReactGA from 'react-ga';
if (!isServer) {
history.listen(location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
});
}
const App = () => (
<div style={{ height: '100%' }}>
<Router history={history}>
<Switch>
{allRoutes.filter(route => route.visible).map((route, index) => {
return (
<Route
exact={route.exact}
path={route.path}
key={index}
component={(route.component)}
/>
)
})}
<Route
path={'/:404_path'}
key={'404'}
component={NotFound}
/>
<Redirect to="/login" />
</Switch>
</Router>
<BackboneModals />
</div>
);
App.displayName = 'App'
function mapStateToProps(state) {
return state.login;
}
export default connect(mapStateToProps)(App);

View File

@ -0,0 +1,61 @@
import {
postApi
} from '../api';
import * as types from '../constants/changePassword'
import errors from '../errors'
export function changePasswordRequest(promise) {
return {
type: types.CHANGEPASSWORD_REQUEST,
payload: promise
};
}
export function changePasswordError(error) {
return {
type: types.CHANGEPASSWORD_FAILED,
payload: error
};
}
export function changePasswordSuccess(values) {
return {
type: types.CHANGEPASSWORD_SUCCESS,
payload: values
};
}
export const resetChangePassword = () => {
return {
type: types.RESET_CHANGEPASSWORD,
};
};
// Calls the API to register a user.
export function changePassword(values) {
return function (dispatch) {
var promise = postApi('user/reset-password', values);
dispatch(changePasswordRequest(promise));
promise.then(function (response) {
dispatch(changePasswordSuccess(response.data));
}, function (error) {
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(changePasswordError(errors(error)));
});
};
}

84
accounts/src/actions/login.js Executable file
View File

@ -0,0 +1,84 @@
import {
postApi
} from '../api';
import * as types from '../constants/login'
import { User, DASHBOARD_URL, DOMAIN_URL } from '../config.js';
import errors from '../errors'
import { getQueryVar } from '../config'
import Cookies from 'universal-cookie';
// There are three possible states for our login
// process and we need actions for each of them
export function loginRequest(promise) {
return {
type: types.LOGIN_REQUEST,
payload: promise
};
}
export function loginError(error) {
return {
type: types.LOGIN_FAILED,
payload: error
};
}
export function loginSuccess(user) {
if (user.redirect) return window.location = `${user.redirect}?accessToken=${user.tokens.jwtAccessToken}`;
//save user session details.
User.setUserId(user.id);
User.setAccessToken(user.tokens.jwtAccessToken);
User.setEmail(user.email);
User.setName(user.name);
User.setCardRegistered(user.cardRegistered);
//share localStorage with dashboard app
const cookies = new Cookies();
var userData = user;
cookies.set('data', userData, { path: '/', maxAge: 30, domain: DOMAIN_URL });
window.location = DASHBOARD_URL
return {
type: types.LOGIN_SUCCESS,
payload: user
};
}
export const resetLogin = () => {
return {
type: types.RESET_LOGIN,
};
};
// Calls the API to register a user.
export function loginUser(values) {
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl)
values.redirect = redirect;
return function (dispatch) {
var promise = postApi('user/login', values);
dispatch(loginRequest(promise));
promise.then(function (user) {
dispatch(loginSuccess(user.data));
}, function (error) {
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(loginError(errors(error)));
});
return promise;
};
}

16
accounts/src/actions/modal.js Executable file
View File

@ -0,0 +1,16 @@
import * as types from '../constants/modal'
export const openModal = function(obj) {
return {
type: types.OPEN_MODAL,
payload: obj
};
}
export const closeModal = function(obj) {
return {
type: types.CLOSE_MODAL,
payload: obj
};
}

174
accounts/src/actions/register.js Executable file
View File

@ -0,0 +1,174 @@
import {
postApi
} from '../api';
import * as types from '../constants/register'
import errors from '../errors'
// There are three possible states for our login
// process and we need actions for each of them
export function signupError(error) {
return {
type: types.SIGNUP_FAILED,
payload: error
};
}
export function saveUserState(values) {
return {
type: types.SAVE_USER_STATE,
payload: values
};
}
export function saveCardState(values) {
return {
type: types.SAVE_CARD_STATE,
payload: values
};
}
export function saveCompanyState(values) {
return {
type: types.SAVE_COMPANY_STATE,
payload: values
};
}
export function signUpRequest(promise) {
return {
type: types.SIGNUP_REQUEST,
payload: promise
};
}
export function signUpReset() {
return {
type: types.RESET_SIGNUP,
};
}
export function signupSuccess(user) {
return {
type: types.SIGNUP_SUCCESS,
payload: user
}
}
export const resetSignup = () => {
return {
type: types.RESET_SIGNUP,
};
};
// Calls the API to register a user.
export function signupUser(values) {
return function (dispatch) {
var promise = postApi('user/signup', values);
dispatch(signUpRequest(promise));
promise.then(function (user) {
dispatch(signupSuccess(user.data));
}, function (error) {
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(signupError(errors(error)));
});
return promise;
};
}
//np payload for inc and dec action creators.
export const incrementStep = () => {
return {
type: types.SIGNUP_STEP_INC,
};
};
//np payload for inc and dec action creators.
export const skipCardStep = () => {
return {
type: types.SKIP_CARD_STEP,
};
};
export const decrementStep = () => {
return {
type: types.SIGNUP_STEP_DEC,
};
};
// There are three possible states for our login
// process and we need actions for each of them
export function isUserInvitedRequest(promise) {
return {
type: types.IS_USER_INVITED_REQUEST,
payload: promise
};
}
export function isUserInvitedReset() {
return {
type: types.IS_USER_INVITED_RESET,
};
}
export function isUserInvitedError(error) {
return {
type: types.IS_USER_INVITED_RESET,
payload: error
};
}
export function isUserInvitedSuccess(data) {
return {
type: types.IS_USER_INVITED_SUCCESS,
payload:data
};
}
export const resetIsUserInvited = () => {
return {
type: types.IS_USER_INVITED_RESET,
};
};
// Calls the API to register a user.
export function isUserInvited(values) {
return function (dispatch) {
var promise = postApi('user/isInvited', values);
dispatch(isUserInvitedRequest(promise));
promise.then(function (response) {
dispatch(isUserInvitedSuccess(response.data));
}, function (error) {
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(isUserInvitedError(errors(error)));
});
return promise;
};
}

View File

@ -0,0 +1,51 @@
import { postApi } from '../api';
import * as types from '../constants/resendToken'
import errors from '../errors'
export function resendTokenRequest(promise) {
return {
type: types.RESENDTOKEN_REQUEST,
payload: promise
};
}
export function resendTokenError(error) {
return {
type: types.RESENDTOKEN_FAILED,
payload: error
};
}
export function resendTokenSuccess(data) {
return {
type: types.RESENDTOKEN_SUCCESS,
payload: data
};
}
export function resendToken(values) {
return function(dispatch){
var promise = postApi('user/resend', values);
dispatch(resendTokenRequest(promise));
promise.then(function(data){
dispatch(resendTokenSuccess(data));
}, function(error){
if(error && error.response && error.response.data)
error = error.response.data;
if(error && error.data){
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(resendTokenError(errors(error)));
});
};
}

View File

@ -0,0 +1,60 @@
import { postApi } from '../api';
import * as types from '../constants/resetPassword'
import errors from '../errors'
// There are three possible states for our resetPassword
// process and we need actions for each of them
export function resetPasswordRequest(promise) {
return {
type: types.PASSWORDRESET_REQUEST,
payload: promise
};
}
export function resetPasswordError(error) {
return {
type: types.PASSWORDRESET_FAILED,
payload: error
};
}
export function resetPasswordSuccess(data) {
return {
type: types.PASSWORDRESET_SUCCESS,
payload: data
};
}
export const resetResetPassword = () => {
return {
type: types.RESET_PASSWORDRESET,
};
};
export function resetPassword(values) {
return function(dispatch){
var promise = postApi('user/forgot-password', values);
dispatch(resetPasswordRequest(promise));
promise.then(function(data){
dispatch(resetPasswordSuccess(data));
}, function(error){
if(error && error.response && error.response.data)
error = error.response.data;
if(error && error.data){
error = error.data;
}
if(error && error.message){
error = error.message;
}
else{
error = 'Network Error';
}
dispatch(resetPasswordError(errors(error)));
});
};
}

135
accounts/src/api.js Executable file
View File

@ -0,0 +1,135 @@
import axios from 'axios';
import {
API_URL
} from './config';
import {
User
} from './config';
import { history } from './store';
var baseURL = API_URL;
var Q = require('q');
var headers = {
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
};
export function postApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
var deffered = Q.defer();
axios({
method: 'POST',
url: `${baseURL}/${url}`,
headers,
data
})
.then(function (response) {
deffered.resolve(response);
})
.catch(function (error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
}
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
deffered.reject(error);
});
return deffered.promise;
}
export function getApi(url) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
var deffered = Q.defer();
axios({
method: 'GET',
url: `${baseURL}/${url}`,
headers
})
.then(function (response) {
deffered.resolve(response);
})
.catch(function (error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
}
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
deffered.reject(error);
});
return deffered.promise;
}
export function putApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
var deffered = Q.defer();
axios({
method: 'PUT',
url: `${baseURL}/${url}`,
headers,
data
})
.then(function (response) {
deffered.resolve(response);
})
.catch(function (error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
}
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
deffered.reject(error);
});
return deffered.promise;
}
export function deleteApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
var deffered = Q.defer();
axios({
method: 'DELETE',
url: `${baseURL}/${url}`,
headers,
data
})
.then(function (response) {
deffered.resolve(response);
})
.catch(function (error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
}
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
}
deffered.reject(error);
});
return deffered.promise;
}

35
accounts/src/components/404.js Executable file
View File

@ -0,0 +1,35 @@
import React, { Component, Fragment } from 'react';
class NotFound extends Component {
render() {
return (
<Fragment>
<div className="db-World-root" >
<div className="db-World-wrapper Box-root Flex-flex Flex-direction--column">
<div>
<div id="app-loading" style={{ 'position': 'fixed', 'top': '0', 'bottom': '0', 'left': '0', 'right': '0', 'zIndex': '1', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center', 'fontSize': '20px', 'flexDirection': 'column' }}>
<div>The page you requested does not exist.</div>
</div>
</div>
</div>
</div>
</Fragment>
)
}
}
NotFound.displayName = 'NotFound'
export default NotFound;

View File

@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types'
export default function MessageBox(props) {
return (
<div id="main-body" className="box css">
<div className="inner">
<div className="request-reset-step step" >
<div className="title">
<h2>
{props.title}
</h2>
</div>
<p className="error-message hidden" />
<p className="message">{props.message}</p>
</div>
</div>
</div>
)
}
MessageBox.displayName = 'MessageBox'
MessageBox.propTypes = {
title: PropTypes.string,
message: PropTypes.string,
}

View File

@ -0,0 +1,76 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
const composableComponent = (ComposedComponent) => {
class Modal extends Component {
constructor(props){
super(props);
this.props = props;
this.onClose = this.onClose.bind(this);
this.onConfirm = this.onConfirm.bind(this);
}
onClose =(value)=> {
if (this.props.item.onClose) {
this.props.item.onClose(value);
this.props.onClose(this.props.item);
} else {
this.props.onClose(this.props.item);
}
}
onConfirm = (value)=> {
var _this = this;
if (this.props.item.onConfirm) {
this.props.item.onConfirm(value)
.then(() => _this.props.onClose(_this.props.item),
()=> {})
} else {
this.props.onClose(this.props.item)
}
}
render() {
const { zIndex } = this.props;
const { extraClasses } = this.props.item;
const mainClass = `${extraClasses || ''} modal-dialog-view`;
const modalContainerStyle = {overflowX: 'auto', overflowY: 'scroll', display: 'block', top: '0px'};
return (
<div
className={mainClass}
style={{
zIndex: (zIndex + 1) * 10000
}}
>
<div
className="modal_overlay"
style={{
top: 0,
opacity: 1,
transform: 'none',
display: 'block',
pointerEvents: 'auto'
}}
>
<div className="modal_container" style={modalContainerStyle}>
<ComposedComponent closeThisDialog={this.onClose} confirmThisDialog={this.onConfirm} />
</div>
</div>
</div>
);
}
}
Modal.propTypes = {
onConfirm: PropTypes.func,
item: PropTypes.object.isRequired,
onClose:PropTypes.func.isRequired,
extraClasses: PropTypes.string,
zIndex: PropTypes.number.isRequired
}
Modal.displayName = 'Modal'
return Modal;
}
export default composableComponent;

View File

@ -0,0 +1,258 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import RenderCountrySelector from '../basic/CountrySelector';
import { connect } from 'react-redux';
import { RenderField } from '../basic/RenderField'
import { PricingPlan } from '../../config';
import { Validate } from '../../config';
import { FlatLoader } from '../basic/Loader.js';
class CardForm extends Component {
render() {
this.plan = PricingPlan.getPlanById(this.props.planId);
return (
<div id="main-body" className="box css">
<div className="inner">
<div className="title extra">
<div>
<h2>
<span> {this.props.register.error ? <span className="error" >{this.props.register.error}</span> : 'Enter your card details'}
</span>
</h2>
<p>Your card will be charged $1.00 to check its billability. You will be charged ${this.plan.amount}/{this.plan.type === 'month' ? 'mo' : 'yr'} after your 14 day free trial.</p>
</div>
</div>
<form id="card-form" onSubmit={this.props.handleSubmit(this.props.submitForm)}>
<p className="text">
<span>
<label htmlFor="cardName">Card Holder Name</label>
<Field
type="text"
name="cardName"
id="cardName"
placeholder="Card Holder Name"
component={RenderField}
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="cardNumber">Card Number</label>
<Field
type="text"
component={RenderField}
name="cardNumber"
id="cardNumber"
placeholder="1234 4534 2322 1234"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="cvv">CVV</label>
<Field
type="password"
component={RenderField}
name="cvc"
id="cvv"
placeholder="CVV"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="expiry">Expiry Date</label>
<Field
type="text"
component={RenderField}
name="expiry"
id="expiry"
placeholder="01/2019"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="address1">Street Address 1</label>
<Field
type="text"
component={RenderField}
name="address1"
id="address1"
placeholder="Street Address 1"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="address2">Street Address 2</label>
<Field
type="text"
component={RenderField}
name="address2"
id="address2"
placeholder="Street Address 2"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="city">City</label>
<Field
type="text"
component={RenderField}
name="city"
id="city"
placeholder="City"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="state">State</label>
<Field
type="text"
component={RenderField}
name="state"
id="state"
placeholder="State (Optional)"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="zipCode">Zip Code / Postal Code</label>
<Field
type="text"
component={RenderField}
name="zipCode"
id="zipCode"
placeholder="Zip Code or Postal Code"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="country">Country</label>
<Field
type="text"
component={RenderCountrySelector}
name="country"
id="country"
placeholder="Select Country"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="promocode">Promo Code(optional)</label>
<Field
type="text"
component={RenderField}
name="promocode"
id="promocode"
placeholder="Promocode (Optional)"
/>
</span>
</p>
<div>
<p className="submit">
<button type="submit" className="button blue medium" id="create-account-button" disabled={this.props.register.requesting}>
{!this.props.register.requesting && <span>Create Fyipe Account</span>}
{this.props.register.requesting && <FlatLoader />}
</button>
</p>
</div>
</form>
</div>
</div>
)
}
}
CardForm.displayName = 'CardForm'
let validate = function (values) {
const errors = {};
if (!Validate.text(values.cardName)) {
errors.cardName = 'Name is required.'
}
if (!Validate.text(values.cardNumber)) {
errors.cardNumber = 'Card Number is required'
}
if (!Validate.text(values.cvc)) {
errors.cvc = 'CVV is required.'
}
if (!Validate.text(values.expiry)) {
errors.expiry = 'Expiry date is required.'
}
if (!Validate.text(values.city)) {
errors.city = 'City is required.'
}
if (!Validate.text(values.zipCode)) {
errors.zipCode = 'Zip Code or Postal Code is required.'
}
if (!Validate.text(values.country)) {
errors.country = 'Country is required.';
}
if (!Validate.card(values.cardNumber)) {
errors.cardNumber = 'Incorrect card number.';
}
if (!Validate.cardExpiration(values.expiry)) {
errors.expiry = 'Expiration date is invalid.';
}
if (!Validate.cvv(values.cvc)) {
errors.cvc = 'CVV is invalid.';
}
if (!Validate.postalCode(values.zipCode)) {
errors.zipCode = 'Postal Code or Zip Code is invalid.';
}
return errors;
};
let cardForm = reduxForm({
form: 'CardForm', // <------ same form name // <----- validate form data
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true, // <------ unregister fields on unmount
validate
})(CardForm);
const mapDispatchToProps = (dispatch_Ignored) => {
return {
}
}
function mapStateToProps(state) {
return {
register: state.register
};
}
CardForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
submitForm: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
planId: PropTypes.string.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(cardForm);

View File

@ -0,0 +1,117 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../../config';
import { FlatLoader } from '../basic/Loader.js';
import { changePasswordError, changePasswordSuccess, changePassword, resetChangePassword } from '../../actions/changePassword';
import { bindActionCreators } from 'redux';
import { RenderField } from '../basic/RenderField';
import { Link } from 'react-router-dom'
export class ChangePasswordForm extends Component {
submitForm =(values)=> {
values.token = this.props.token || '';
this.props.changePassword(values);
}
render() {
return (
<div id="main-body" className="box css">
<div className="inner">
<form onSubmit={this.props.handleSubmit(this.submitForm)} className="request-reset">
<div className="request-reset-step step" >
<div className="title">
<h2>
<span > {this.props.changePasswordState.error ? <span className="error" >{this.props.changePasswordState.error}</span> : 'Reset Password'} </span>
</h2>
</div>
<p className="error-message hidden" />
{this.props.changePasswordState.success && <p className="message"> Your password is changed. Please <Link to="/login"> click here to login </Link> </p>}
{!this.props.changePasswordState.success && <p className="message"> Enter your email address below and we will send you a link to
reset your password. </p>}
{!this.props.changePasswordState.success && <div> <p className="text">
<span>
<label htmlFor="password"> Password </label>
<Field
component={RenderField}
type="password"
name="password"
id="password"
placeholder="Password"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="confirmPassword"> Confirm Password </label>
<Field
component={RenderField}
type="password"
name="confirmPassword"
id="confirmPassword"
placeholder="Confirm Password"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" disabled={this.props.changePasswordState.requesting}>
{!this.props.changePasswordState.requesting && <span>Change Password</span>}
{this.props.changePasswordState.requesting && <FlatLoader />}
</button>
</p> </div>}
</div>
</form>
</div>
</div>
)
}
}
ChangePasswordForm.displayName = 'ChangePasswordForm'
function validate(values) {
let errors = {};
if (!Validate.text(values.password)) {
errors.password = 'Password is required.'
}
if (!Validate.text(values.confirmPassword)) {
errors.confirmPassword = 'Confirm Password is invalid.'
}
return errors;
}
let changePasswordForm = reduxForm({
form: 'changePasswordForm', // a unique identifier for this form
validate
})(ChangePasswordForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
changePasswordError, changePasswordSuccess, changePassword, resetChangePassword
}, dispatch);
};
function mapStateToProps(state) {
return {
changePasswordState: state.changePassword
};
}
ChangePasswordForm.propTypes = {
changePassword: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
changePasswordState: PropTypes.object.isRequired,
token: PropTypes.any
}
export default connect(mapStateToProps, mapDispatchToProps)(changePasswordForm);

View File

@ -0,0 +1,182 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import CountrySelector from '../basic/CountrySelector';
import CompanySizeSelector from '../basic/CompanySizeSelector';
import { connect } from 'react-redux';
import {RenderField} from '../basic/RenderField'
import {Validate} from '../../config';
import {FlatLoader} from '../basic/Loader.js';
let errorStyle = {
color:'red'
}
class CompanyForm extends Component {
render() {
return (
<div id="main-body" className="box css">
<div className="inner">
<div className="title extra">
<h2><span> {this.props.register.error ? <span style={errorStyle} > {this.props.register.error}</span> : 'One Last Step...'} </span></h2>
</div>
<form onSubmit={this.props.handleSubmit(this.props.submitForm)}>
<p className="text">
<span>
<label htmlFor="companyName">Company Name</label>
<Field
type="text"
name="companyName"
id="companyName"
component={RenderField}
placeholder="Company Name"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companyRole">Job Title</label>
<Field
type="text"
name="companyRole"
id="companyRole"
component={RenderField}
placeholder="Your Job Title"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companyCountry">Country</label>
<Field
type="text"
component={CountrySelector}
name="companyCountry"
id="companyCountry"
placeholder="Company Country"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companySize">Company Size</label>
<Field
type="text"
component={CompanySizeSelector}
name="companySize"
id="companySize"
placeholder="company Size"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companyPhoneNumber">Phone Number</label>
<Field
type="text"
component={RenderField}
name="companyPhoneNumber"
id="companyPhoneNumber"
placeholder="+1-123-456-7890"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="reference">Where did you hear about us?</label>
<Field
type="text"
component={RenderField}
name="reference"
id="reference"
placeholder="e.g Facebook"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="reference">Promo Code(optional)</label>
<Field
type="text"
component={RenderField}
name="promocode"
id="promocode"
placeholder="Promocode (Optional)"
/>
</span>
</p>
<div>
<p className="submit">
<button type="submit" className="button blue medium" id="create-account-button" disabled={this.props.register.requesting}>
{ !this.props.register.requesting && <span>Create Fyipe Account</span> }
{ this.props.register.requesting && <FlatLoader /> }
</button>
</p>
</div>
</form>
</div>
</div>
)
}
}
CompanyForm.displayName = 'CompanyForm'
let validate = function(values){
let error = {};
if(!Validate.text(values.companyName)){
error.companyName = 'Company name is required.'
}
if(!Validate.text(values.companyRole)){
error.companyRole = 'Job Title is required.'
}
if(!Validate.text(values.companyPhoneNumber)){
error.companyPhoneNumber ='Phone Number is required.'
}
if(!Validate.text(values.comapnySize)){
error.comapnySize ='Phone Number is required.'
}
if(!Validate.text(values.reference)){
error.reference ='This is required.'
}
return error;
}
let companyForm = reduxForm({
form: 'CompanyForm', // <------ same form name
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true,
validate // <------ unregister fields on unmoun
})(CompanyForm);
const mapDispatchToProps = (dispatch_Ignored) => {
return {
}
}
function mapStateToProps(state) {
return {
register: state.register
};
}
CompanyForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
submitForm: PropTypes.func.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(companyForm);

View File

@ -0,0 +1,146 @@
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form';
import { RenderField } from '../basic/RenderField';
import { connect } from 'react-redux';
import { Validate } from '../../config';
import { FlatLoader } from '../basic/Loader.js';
import { loginError, loginSuccess, loginUser, resetLogin } from '../../actions/login';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import queryString from 'query-string';
import { removeQuery } from '../../store';
export class LoginForm extends Component {
state = {
serverResponse: ''
}
componentDidMount() {
const query = queryString.parse(this.props.location.search).status;
var serverResponse = '';
if (query === 'IIYQNdn4impaXQeeteTBEBmz0If1rlwC') {
serverResponse = 'Email already verified. You can now login.'
}
else if (query === 'V0JvLGX4U0lgO9Z9ulrOXFW9pNSGLSnP') {
serverResponse = 'Thank you for verifying your email. You can now login.'
}
this.setState({
serverResponse
});
removeQuery('status');
}
render() {
const { handleSubmit } = this.props;
const { serverResponse } = this.state;
return (
<div id="main-body" className="box css">
<div className="inner login">
<div>
<form onSubmit={handleSubmit(this.props.onSubmit)}>
<div className="step email-password-step">
<h2>
{serverResponse ? (<span>{serverResponse}</span>) :
(<span > {this.props.login.error ? <span className="error" >{this.props.login.error}</span> : 'Welcome back!'} </span>
)}
</h2>
<p className="text">
<span>
<label htmlFor="email">
<span>Email</span>
</label>
<Field className="error"
component={RenderField}
type="email"
name="email"
id="email"
placeholder="jeff@example.com"
required="required"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="password">
<span>Password</span>
</label>
<Field
component={RenderField}
type="password"
name="password"
id="password"
placeholder="Your Password"
required="required"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" id="login-button" disabled={this.props.login.requesting}>
{!this.props.login.requesting && <span>Sign in to your account</span>}
{this.props.login.requesting && <FlatLoader />}
</button>
</p>
</div>
</form>
</div>
</div>
</div>
)
}
}
LoginForm.displayName = 'LoginForm'
let validate = function (values) {
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
else {
if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
}
if (!Validate.text(values.password)) {
errors.password = 'Password is required.'
}
return errors;
}
let loginForm = reduxForm({
form: 'LoginForm', // a unique identifier for this form
validate,
destroyOnUnmount: false
})(LoginForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
loginError, loginSuccess, loginUser, resetLogin
}, dispatch);
};
function mapStateToProps(state) {
return {
login: state.login
};
}
LoginForm.contextTypes = {
mixpanel: PropTypes.object.isRequired
};
LoginForm.propTypes = {
onSubmit: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
login: PropTypes.object.isRequired,
location: PropTypes.object.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(loginForm);

View File

@ -0,0 +1,117 @@
import React, { Component } from 'react'
import { reduxForm } from 'redux-form'
import UserForm from './UserForm';
import CardForm from './CardForm';
import { connect } from 'react-redux';
import { signupError, signupSuccess, signupUser, incrementStep, decrementStep, resetSignup, saveUserState, saveCardState, isUserInvited } from '../../actions/register'
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
export class RegisterForm extends Component {
constructor(props) {
super(props);
this.props = props;
}
userFormSubmitted = (values) => {
let thisObj = this;
this.props.saveUserState(values);
this.props.isUserInvited(values).then(function (value) {
if (value.data) {
thisObj.props.signupUser({...values, planId: thisObj.props.planId })
.then((user) => {
if (user && user.data && user.data.id) {
if (window.location.href.indexOf('localhost') <= -1) {
thisObj.context.mixpanel.identify(user.data.id);
thisObj.context.mixpanel.people.set({
'$first_name': user.data.name,
'$created': new Date(),
'$email': user.data.email
});
thisObj.context.mixpanel.track('user registered', { 'First Time': 'TRUE', 'id': user.data.id });
}
}
})
} else {
thisObj.props.incrementStep();
}
}, function (error) {
return error
});
}
cardFormSubmitted = (values) => {
var thisObj = this;
this.props.saveCardState(values);
this.props.signupUser({ ...this.props.register.user, ...values, planId: this.props.planId })
.then((user) => {
if (user && user.data && user.data.id) {
if (window.location.href.indexOf('localhost') <= -1) {
thisObj.context.mixpanel.identify(user.data.id);
thisObj.context.mixpanel.people.set({
'$first_name': user.data.name,
'$created': new Date(),
'$email': user.data.email
});
thisObj.context.mixpanel.track('user registered', { 'First Time': 'TRUE', 'id': user.data.id });
}
}
})
}
render() {
return (
<div>
{this.props.register.step === 1 && <UserForm submitForm={this.userFormSubmitted} error={this.props.register.error} location={this.props.location} />}
{this.props.register.step === 2 && <CardForm planId={this.props.planId} submitForm={this.cardFormSubmitted} error={this.props.register.error} />}
</div>
)
}
}
RegisterForm.displayName = 'RegisterForm'
let registerForm = reduxForm({
form: 'RegisterForm'
})(RegisterForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
signupError,
signupSuccess,
signupUser,
incrementStep,
decrementStep,
resetSignup,
saveUserState,
saveCardState,
isUserInvited,
}, dispatch);
};
function mapStateToProps(state) {
return {
register: state.register
};
}
RegisterForm.contextTypes = {
mixpanel: PropTypes.object.isRequired
};
RegisterForm.propTypes = {
signupUser: PropTypes.func.isRequired,
saveCardState: PropTypes.func.isRequired,
//incrementStep: PropTypes.func.isRequired,
saveUserState: PropTypes.func.isRequired,
isUserInvited: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
planId: PropTypes.string.isRequired,
location: PropTypes.object.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(registerForm);

View File

@ -0,0 +1,104 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../../config';
import { FlatLoader } from '../basic/Loader.js';
import { resetPasswordError, resetPasswordSuccess, resetPassword, resetResetPassword } from '../../actions/resetPassword';
import { bindActionCreators } from 'redux';
import { RenderField } from '../basic/RenderField';
export class ResetPasswordForm extends Component {
submitForm = (values) => {
this.props.resetPassword(values);
}
render() {
return (
<div id="main-body" className="box css">
<div className="inner">
<form onSubmit={this.props.handleSubmit(this.submitForm)} className="request-reset">
<div className="request-reset-step step" >
<div className="title">
<h2>
<span > {this.props.resetPasswordState.error ? <span id="error-msg" className="error" >{this.props.resetPasswordState.error}</span> : 'Reset Password'} </span>
</h2>
</div>
<p className="error-message hidden" />
{this.props.resetPasswordState.success && <p id="reset-password-success" className="message"> An email is on its way to you. Follow the instructions to
reset your password. Please don&apos;t forget to check spam. </p>}
{!this.props.resetPasswordState.success && <p className="message"> Enter your email address below and we will send you a link to
reset your password. </p>}
{!this.props.resetPasswordState.success && <div> <p className="text">
<span>
<label htmlFor="email"> Your Email</label>
<Field
component={RenderField}
type="email"
name="email"
id="email"
placeholder="Your Email"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" disabled={this.props.resetPasswordState.requesting}>
{!this.props.resetPasswordState.requesting && <span>Reset Password</span>}
{this.props.resetPasswordState.requesting && <FlatLoader />}
</button>
</p> </div>}
</div>
</form>
</div>
</div>
)
}
}
ResetPasswordForm.displayName = 'ResetPasswordForm'
function validate(values) {
let errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
return errors;
}
let resetPasswordForm = reduxForm({
form: 'resetPasswordForm', // a unique identifier for this form
validate
})(ResetPasswordForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
resetPasswordError, resetPasswordSuccess, resetPassword, resetResetPassword
}, dispatch);
};
function mapStateToProps(state) {
return {
resetPasswordState: state.resetPassword
};
}
ResetPasswordForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
resetPasswordState: PropTypes.object.isRequired,
resetPassword: PropTypes.func.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(resetPasswordForm);

View File

@ -0,0 +1,203 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Validate } from '../../config';
import { RenderField } from '../basic/RenderField';
import { FlatLoader } from '../basic/Loader.js';
import { removeQuery } from '../../store';
import queryString from 'query-string';
class UserForm extends Component {
state = {
serverResponse: ''
}
componentDidMount() {
var query = queryString.parse(this.props.location.search).status;
if (query === 'z1hb0g8vfg0rWM1Ly1euQSZ1L5ZNHuAk') {
this.setState({
serverResponse: 'No user found for this token'
});
}
removeQuery();
}
render() {
const { serverResponse } = this.state;
return (
<div id="main-body" className="box css">
<div className="inner">
<div className="title extra">
<h2>
{
serverResponse ? <span>{serverResponse}</span> :
<span> {this.props.register.error ? <span id="error-msg" className="error" >{this.props.register.error}</span> : 'Create your Fyipe account.'} </span>
}
</h2>
</div>
<form onSubmit={this.props.handleSubmit(this.props.submitForm)}>
<p className="text">
<span id="ema">
<label htmlFor="email">Email</label>
<Field
type="email"
id="email"
name="email"
component={RenderField}
placeholder="jeff@example.com"
required="required"
value={this.props.register.user.email || ''}
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="name">Full Name</label>
<Field
type="text"
component={RenderField}
name="name"
id="name"
placeholder="Jeff Smith"
required="required"
value={this.props.register.user.name || ''}
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companyName">Company Name</label>
<Field
type="text"
name="companyName"
id="companyName"
component={RenderField}
placeholder="Company Name"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="companyPhoneNumber">Phone Number</label>
<Field
type="text"
component={RenderField}
name="companyPhoneNumber"
id="companyPhoneNumber"
placeholder="+1-123-456-7890"
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="password">Password</label>
<Field
type="password"
component={RenderField}
name="password"
id="password"
placeholder="Your Password"
className="password-strength-input"
required="required"
value={this.props.register.user.password || ''}
/>
</span>
</p>
<p className="text">
<span>
<label htmlFor="confirmPassword">Confirm Password</label>
<Field
type="password"
component={RenderField}
name="confirmPassword"
id="confirmPassword"
placeholder="Confirm Password"
required="required"
value={this.props.register.user.confirmPassword || ''}
/>
</span>
</p>
<div>
<p className="submit">
<button type="submit" className="button blue medium" id="create-account-button" disabled={this.props.register && ((this.props.register.isUserInvited && this.props.register.isUserInvited.requesting) || this.props.register.requesting )}>
{this.props.register && ((this.props.register.isUserInvited && this.props.register.isUserInvited.requesting) || this.props.register.requesting ) ? <FlatLoader /> : <span>Create Fyipe Account</span>}
</button>
</p>
</div>
</form>
</div>
</div>
)
}
}
UserForm.displayName = 'UserForm'
let validate = function (values) {
let error = {};
if (!Validate.text(values.name))
error.name = 'Name is required.';
if (!Validate.text(values.email))
error.email = 'Email is required.';
if (Validate.text(values.email) && !Validate.email(values.email))
error.email = 'Email is not valid.';
if (!Validate.isValidBusinessEmail(values.email) && Validate.email(values.email))
error.email = 'Please enter a business email address.';
if (!Validate.text(values.companyName))
error.companyName = 'Company name is required.';
if (!Validate.text(values.companyPhoneNumber))
error.companyPhoneNumber = 'Phone number is required.';
if (!Validate.text(values.password))
error.password = 'Password is required.';
if (!Validate.text(values.confirmPassword))
error.confirmPassword = 'Confirm Password is required.';
if (!Validate.compare(values.password, values.confirmPassword)) {
error.confirmPassword = 'Password and confirm password should match.';
}
return error;
}
let userForm = reduxForm({
form: 'UserSignupForm', // <------ same form name
destroyOnUnmount: false,
validate
})(UserForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
}, dispatch);
}
function mapStateToProps(state) {
return {
register: state.register
};
}
UserForm.propTypes = {
submitForm: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
location: PropTypes.object.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(userForm);

View File

@ -0,0 +1,7 @@
export const companySize = [
{ name: '1-10', code: '1-10' },
{ name: '11-50', code: '11-50' },
{ name: '51-200', code: '51-200' },
{ name: '200-1000', code: '200-1000' },
{ name: '1000+', code: '1000+' }
];

View File

@ -0,0 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types'
import { companySize } from './CompanySizeList';
let errorStyle = {
color: 'red',
topMargin: '5px'
}
const CompanySizeSelector = ({ input, id, meta: { touched, error } }) => (
<span>
<select {...input} className="selector" id={id}>
<option value="">Select Company Size...</option>
{companySize.map(val => (
<option value={val.name} key={val.code}>
{val.name}
</option>
))}
</select>
{touched && error && <span style={errorStyle}>{error}</span>}
</span>
)
CompanySizeSelector.displayName = 'CompanySizeSelector'
CompanySizeSelector.propTypes = {
meta: PropTypes.object.isRequired,
input: PropTypes.object.isRequired,
id: PropTypes.string
}
export default CompanySizeSelector

View File

@ -0,0 +1,245 @@
export const countries = [
{ name: 'Afghanistan', code: 'AF' },
{ name: 'Åland Islands', code: 'AX' },
{ name: 'Albania', code: 'AL' },
{ name: 'Algeria', code: 'DZ' },
{ name: 'American Samoa', code: 'AS' },
{ name: 'AndorrA', code: 'AD' },
{ name: 'Angola', code: 'AO' },
{ name: 'Anguilla', code: 'AI' },
{ name: 'Antarctica', code: 'AQ' },
{ name: 'Antigua and Barbuda', code: 'AG' },
{ name: 'Argentina', code: 'AR' },
{ name: 'Armenia', code: 'AM' },
{ name: 'Aruba', code: 'AW' },
{ name: 'Australia', code: 'AU' },
{ name: 'Austria', code: 'AT' },
{ name: 'Azerbaijan', code: 'AZ' },
{ name: 'Bahamas', code: 'BS' },
{ name: 'Bahrain', code: 'BH' },
{ name: 'Bangladesh', code: 'BD' },
{ name: 'Barbados', code: 'BB' },
{ name: 'Belarus', code: 'BY' },
{ name: 'Belgium', code: 'BE' },
{ name: 'Belize', code: 'BZ' },
{ name: 'Benin', code: 'BJ' },
{ name: 'Bermuda', code: 'BM' },
{ name: 'Bhutan', code: 'BT' },
{ name: 'Bolivia', code: 'BO' },
{ name: 'Bosnia and Herzegovina', code: 'BA' },
{ name: 'Botswana', code: 'BW' },
{ name: 'Bouvet Island', code: 'BV' },
{ name: 'Brazil', code: 'BR' },
{ name: 'British Indian Ocean Territory', code: 'IO' },
{ name: 'Brunei Darussalam', code: 'BN' },
{ name: 'Bulgaria', code: 'BG' },
{ name: 'Burkina Faso', code: 'BF' },
{ name: 'Burundi', code: 'BI' },
{ name: 'Cambodia', code: 'KH' },
{ name: 'Cameroon', code: 'CM' },
{ name: 'Canada', code: 'CA' },
{ name: 'Cape Verde', code: 'CV' },
{ name: 'Cayman Islands', code: 'KY' },
{ name: 'Central African Republic', code: 'CF' },
{ name: 'Chad', code: 'TD' },
{ name: 'Chile', code: 'CL' },
{ name: 'China', code: 'CN' },
{ name: 'Christmas Island', code: 'CX' },
{ name: 'Cocos (Keeling) Islands', code: 'CC' },
{ name: 'Colombia', code: 'CO' },
{ name: 'Comoros', code: 'KM' },
{ name: 'Congo', code: 'CG' },
{ name: 'Congo, The Democratic Republic of the', code: 'CD' },
{ name: 'Cook Islands', code: 'CK' },
{ name: 'Costa Rica', code: 'CR' },
{ name: 'Cote d\'Ivoire', code: 'CI' },
{ name: 'Croatia', code: 'HR' },
{ name: 'Cuba', code: 'CU' },
{ name: 'Cyprus', code: 'CY' },
{ name: 'Czech Republic', code: 'CZ' },
{ name: 'Denmark', code: 'DK' },
{ name: 'Djibouti', code: 'DJ' },
{ name: 'Dominica', code: 'DM' },
{ name: 'Dominican Republic', code: 'DO' },
{ name: 'Ecuador', code: 'EC' },
{ name: 'Egypt', code: 'EG' },
{ name: 'El Salvador', code: 'SV' },
{ name: 'Equatorial Guinea', code: 'GQ' },
{ name: 'Eritrea', code: 'ER' },
{ name: 'Estonia', code: 'EE' },
{ name: 'Ethiopia', code: 'ET' },
{ name: 'Falkland Islands (Malvinas)', code: 'FK' },
{ name: 'Faroe Islands', code: 'FO' },
{ name: 'Fiji', code: 'FJ' },
{ name: 'Finland', code: 'FI' },
{ name: 'France', code: 'FR' },
{ name: 'French Guiana', code: 'GF' },
{ name: 'French Polynesia', code: 'PF' },
{ name: 'French Southern Territories', code: 'TF' },
{ name: 'Gabon', code: 'GA' },
{ name: 'Gambia', code: 'GM' },
{ name: 'Georgia', code: 'GE' },
{ name: 'Germany', code: 'DE' },
{ name: 'Ghana', code: 'GH' },
{ name: 'Gibraltar', code: 'GI' },
{ name: 'Greece', code: 'GR' },
{ name: 'Greenland', code: 'GL' },
{ name: 'Grenada', code: 'GD' },
{ name: 'Guadeloupe', code: 'GP' },
{ name: 'Guam', code: 'GU' },
{ name: 'Guatemala', code: 'GT' },
{ name: 'Guernsey', code: 'GG' },
{ name: 'Guinea', code: 'GN' },
{ name: 'Guinea-Bissau', code: 'GW' },
{ name: 'Guyana', code: 'GY' },
{ name: 'Haiti', code: 'HT' },
{ name: 'Heard Island and Mcdonald Islands', code: 'HM' },
{ name: 'Holy See (Vatican City State)', code: 'VA' },
{ name: 'Honduras', code: 'HN' },
{ name: 'Hong Kong', code: 'HK' },
{ name: 'Hungary', code: 'HU' },
{ name: 'Iceland', code: 'IS' },
{ name: 'India', code: 'IN' },
{ name: 'Indonesia', code: 'ID' },
{ name: 'Iran, Islamic Republic Of', code: 'IR' },
{ name: 'Iraq', code: 'IQ' },
{ name: 'Ireland', code: 'IE' },
{ name: 'Isle of Man', code: 'IM' },
{ name: 'Israel', code: 'IL' },
{ name: 'Italy', code: 'IT' },
{ name: 'Jamaica', code: 'JM' },
{ name: 'Japan', code: 'JP' },
{ name: 'Jersey', code: 'JE' },
{ name: 'Jordan', code: 'JO' },
{ name: 'Kazakhstan', code: 'KZ' },
{ name: 'Kenya', code: 'KE' },
{ name: 'Kiribati', code: 'KI' },
{ name: 'Korea, Democratic People\'s Republic of', code: 'KP' },
{ name: 'Korea, Republic of', code: 'KR' },
{ name: 'Kuwait', code: 'KW' },
{ name: 'Kyrgyzstan', code: 'KG' },
{ name: 'Lao People\'s Democratic Republic', code: 'LA' },
{ name: 'Latvia', code: 'LV' },
{ name: 'Lebanon', code: 'LB' },
{ name: 'Lesotho', code: 'LS' },
{ name: 'Liberia', code: 'LR' },
{ name: 'Libyan Arab Jamahiriya', code: 'LY' },
{ name: 'Liechtenstein', code: 'LI' },
{ name: 'Lithuania', code: 'LT' },
{ name: 'Luxembourg', code: 'LU' },
{ name: 'Macao', code: 'MO' },
{ name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK' },
{ name: 'Madagascar', code: 'MG' },
{ name: 'Malawi', code: 'MW' },
{ name: 'Malaysia', code: 'MY' },
{ name: 'Maldives', code: 'MV' },
{ name: 'Mali', code: 'ML' },
{ name: 'Malta', code: 'MT' },
{ name: 'Marshall Islands', code: 'MH' },
{ name: 'Martinique', code: 'MQ' },
{ name: 'Mauritania', code: 'MR' },
{ name: 'Mauritius', code: 'MU' },
{ name: 'Mayotte', code: 'YT' },
{ name: 'Mexico', code: 'MX' },
{ name: 'Micronesia, Federated States of', code: 'FM' },
{ name: 'Moldova, Republic of', code: 'MD' },
{ name: 'Monaco', code: 'MC' },
{ name: 'Mongolia', code: 'MN' },
{ name: 'Montserrat', code: 'MS' },
{ name: 'Morocco', code: 'MA' },
{ name: 'Mozambique', code: 'MZ' },
{ name: 'Myanmar', code: 'MM' },
{ name: 'Namibia', code: 'NA' },
{ name: 'Nauru', code: 'NR' },
{ name: 'Nepal', code: 'NP' },
{ name: 'Netherlands', code: 'NL' },
{ name: 'Netherlands Antilles', code: 'AN' },
{ name: 'New Caledonia', code: 'NC' },
{ name: 'New Zealand', code: 'NZ' },
{ name: 'Nicaragua', code: 'NI' },
{ name: 'Niger', code: 'NE' },
{ name: 'Nigeria', code: 'NG' },
{ name: 'Niue', code: 'NU' },
{ name: 'Norfolk Island', code: 'NF' },
{ name: 'Northern Mariana Islands', code: 'MP' },
{ name: 'Norway', code: 'NO' },
{ name: 'Oman', code: 'OM' },
{ name: 'Pakistan', code: 'PK' },
{ name: 'Palau', code: 'PW' },
{ name: 'Palestinian Territory, Occupied', code: 'PS' },
{ name: 'Panama', code: 'PA' },
{ name: 'Papua New Guinea', code: 'PG' },
{ name: 'Paraguay', code: 'PY' },
{ name: 'Peru', code: 'PE' },
{ name: 'Philippines', code: 'PH' },
{ name: 'Pitcairn', code: 'PN' },
{ name: 'Poland', code: 'PL' },
{ name: 'Portugal', code: 'PT' },
{ name: 'Puerto Rico', code: 'PR' },
{ name: 'Qatar', code: 'QA' },
{ name: 'Reunion', code: 'RE' },
{ name: 'Romania', code: 'RO' },
{ name: 'Russian Federation', code: 'RU' },
{ name: 'RWANDA', code: 'RW' },
{ name: 'Saint Helena', code: 'SH' },
{ name: 'Saint Kitts and Nevis', code: 'KN' },
{ name: 'Saint Lucia', code: 'LC' },
{ name: 'Saint Pierre and Miquelon', code: 'PM' },
{ name: 'Saint Vincent and the Grenadines', code: 'VC' },
{ name: 'Samoa', code: 'WS' },
{ name: 'San Marino', code: 'SM' },
{ name: 'Sao Tome and Principe', code: 'ST' },
{ name: 'Saudi Arabia', code: 'SA' },
{ name: 'Senegal', code: 'SN' },
{ name: 'Serbia and Montenegro', code: 'CS' },
{ name: 'Seychelles', code: 'SC' },
{ name: 'Sierra Leone', code: 'SL' },
{ name: 'Singapore', code: 'SG' },
{ name: 'Slovakia', code: 'SK' },
{ name: 'Slovenia', code: 'SI' },
{ name: 'Solomon Islands', code: 'SB' },
{ name: 'Somalia', code: 'SO' },
{ name: 'South Africa', code: 'ZA' },
{ name: 'South Georgia and the South Sandwich Islands', code: 'GS' },
{ name: 'Spain', code: 'ES' },
{ name: 'Sri Lanka', code: 'LK' },
{ name: 'Sudan', code: 'SD' },
{ name: 'Suriname', code: 'SR' },
{ name: 'Svalbard and Jan Mayen', code: 'SJ' },
{ name: 'Swaziland', code: 'SZ' },
{ name: 'Sweden', code: 'SE' },
{ name: 'Switzerland', code: 'CH' },
{ name: 'Syrian Arab Republic', code: 'SY' },
{ name: 'Taiwan, Province of China', code: 'TW' },
{ name: 'Tajikistan', code: 'TJ' },
{ name: 'Tanzania, United Republic of', code: 'TZ' },
{ name: 'Thailand', code: 'TH' },
{ name: 'Timor-Leste', code: 'TL' },
{ name: 'Togo', code: 'TG' },
{ name: 'Tokelau', code: 'TK' },
{ name: 'Tonga', code: 'TO' },
{ name: 'Trinidad and Tobago', code: 'TT' },
{ name: 'Tunisia', code: 'TN' },
{ name: 'Turkey', code: 'TR' },
{ name: 'Turkmenistan', code: 'TM' },
{ name: 'Turks and Caicos Islands', code: 'TC' },
{ name: 'Tuvalu', code: 'TV' },
{ name: 'Uganda', code: 'UG' },
{ name: 'Ukraine', code: 'UA' },
{ name: 'United Arab Emirates', code: 'AE' },
{ name: 'United Kingdom', code: 'GB' },
{ name: 'United States', code: 'US' },
{ name: 'United States Minor Outlying Islands', code: 'UM' },
{ name: 'Uruguay', code: 'UY' },
{ name: 'Uzbekistan', code: 'UZ' },
{ name: 'Vanuatu', code: 'VU' },
{ name: 'Venezuela', code: 'VE' },
{ name: 'Viet Nam', code: 'VN' },
{ name: 'Virgin Islands, British', code: 'VG' },
{ name: 'Virgin Islands, U.S.', code: 'VI' },
{ name: 'Wallis and Futuna', code: 'WF' },
{ name: 'Western Sahara', code: 'EH' },
{ name: 'Yemen', code: 'YE' },
{ name: 'Zambia', code: 'ZM' },
{ name: 'Zimbabwe', code: 'ZW' }
];

View File

@ -0,0 +1,31 @@
import React from 'react';
import PropTypes from 'prop-types'
import { countries } from './CountryList';
let errorStyle = {
color:'red',
topMargin:'5px'
}
const CountrySelector = ({ input, meta: { touched, error } }) => (
<span>
<select {...input} className="selector" id="country">
<option value="">Select Country...</option>
{countries.map(val => (
<option value={val.name} key={val.code}>
{val.name}
</option>
))}
</select>
{touched && error && <span style={errorStyle}>{error}</span>}
</span>
)
CountrySelector.displayName = 'CountrySelector'
CountrySelector.propTypes = {
meta: PropTypes.object.isRequired,
input: PropTypes.object.isRequired
}
export default CountrySelector

View File

@ -0,0 +1,46 @@
import React, { Component} from 'react';
import PropTypes from 'prop-types';
class ErrorBoundary extends Component{
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
try{
if(window.location.href.indexOf('localhost') <= -1){
this.context.mixpanel.track('An Error has occurred',{error,info});
}
}catch(error){
return error
}
}
render() {
if(this.state.hasError) {
return(
<div id="app-loading" style={{ 'position': 'fixed', 'top': '0', 'bottom': '0', 'left': '0', 'right': '0', 'backgroundColor': '#e6ebf1', 'zIndex': '999', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center' }}>
<div>An unexpected error has occured. Please reload the page to continue</div>
</div>
)
}
return this.props.children;
}
}
ErrorBoundary.displayName = 'ErrorBoundary'
ErrorBoundary.contextTypes = {
mixpanel: PropTypes.object.isRequired
};
ErrorBoundary.propTypes = {
children: PropTypes.any
}
export default ErrorBoundary;

View File

@ -0,0 +1,85 @@
import React from 'react';
let loaderStyle = {
backgroundColor: '#96d8ff'
}
export const FlatLoader = () => (<div className="ball-pulse"><div style={loaderStyle}></div><div style={loaderStyle}></div><div style={loaderStyle}></div></div>);
FlatLoader.displayName = 'FlatLoader'
export const FormLoader = () => (<div className="ball-beat"><div style={{ height: '8px', width: '8px' }}></div><div style={{ height: '8px', width: '8px' }}></div><div style={{ height: '8px', width: '8px' }}></div></div>);
FormLoader.displayName = 'FormLoader'
export const ListLoader = () => (<div className="ball-beat" style={{ textAlign: 'center', marginTop: '20px' }}><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div></div>);
ListLoader.displayName = 'ListLoader'
export const TeamListLoader = () => (<div className="ball-beat" style={{ textAlign: 'center',width:'95px'}}><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#32325d' }}></div></div>);
TeamListLoader.displayName = 'TeamListLoader'
export const Spinner = () => (
<div className="Spinner bs-SpinnerLegacy Spinner--color--white Box-root Flex-inlineFlex Flex-alignItems--center Flex-justifyContent--center">
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="Spinner-svg"
>
<ellipse
cx={12}
cy={12}
rx={10}
ry={10}
className="Spinner-ellipse"
/>
</svg>
</div>
)
Spinner.displayName = 'Spinner'
export const LoadingState = () => (
<div className="Box-root Margin-bottom--12">
<div className="bs-ContentSection Card-root Card-shadow--medium">
<div className="Box-root">
<div className="ContentState Box-root">
<div className="Box-root Padding-horizontal--20 Padding-vertical--48">
<div className="Box-root Flex-flex Flex-alignItems--center Flex-direction--column Flex-justifyContent--flexStart">
<div className="Box-root Margin-bottom--12">
<div className="Box-root">
<div className="Spinner bs-SpinnerLegacy Spinner--size--large Box-root Flex-flex Flex-alignItems--center Flex-justifyContent--center">
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="Spinner-svg"
>
<ellipse
cx={12}
cy={12}
rx={10}
ry={10}
className="Spinner-ellipse"
/>
</svg>
</div>
</div>
</div>
<div className="Box-root">
<div className="Box-root">
<span className="ContentState-title Text-align--center Text-color--secondary Text-display--block Text-fontSize--14 Text-fontWeight--regular Text-lineHeight--20 Text-typeface--base Text-wrap--wrap">
<span>Loading</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
LoadingState.displayName = 'LoadingState'

View File

@ -0,0 +1,54 @@
import React from 'react';
import PropTypes from 'prop-types'
let errorStyle = {
color:'red',
topMargin:'5px'
}
const RenderField = ({ input, placeholder, type, meta, className, id, disabled, initialValue, style }) => (
<span>
<span>
<input
{...input}
type={type}
placeholder={placeholder}
className={className}
id={id}
disabled={disabled || false}
defaultValue={initialValue}
style={style || {}}
/>
</span>
<br/>
{meta.error &&
meta.touched &&
<span style={errorStyle}>
{meta.error}
</span>}
</span>
)
RenderField.displayName = 'RenderField'
RenderField.propTypes = {
initialValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
]),
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
type: PropTypes.string.isRequired,
className: PropTypes.string,
id: PropTypes.string,
meta: PropTypes.object.isRequired,
rows: PropTypes.string,
disabled: PropTypes.bool,
style: PropTypes.object
}
export {RenderField}

359
accounts/src/config.js Executable file
View File

@ -0,0 +1,359 @@
import React from 'react';
import isEmail from 'sane-email-validation';
import validUrl from 'valid-url';
import valid from 'card-validator';
import { isServer } from './store';
import FileSaver from 'file-saver';
import { emaildomains } from './constants/emaildomains';
let apiUrl = 'http://localhost:3002';
let dashboardUrl = null;
let domain = null;
if (!isServer) {
if (window.location.href.indexOf('localhost') > -1) {
apiUrl = 'http://localhost:3002';
dashboardUrl = 'http://localhost:3000';
domain = 'localhost';
} else if (window.location.href.indexOf('staging') > -1) {
apiUrl = 'https://staging-api.fyipe.com';
dashboardUrl = 'http://staging-dashboard.fyipe.com';
domain = 'fyipe.com';
} else {
apiUrl = 'https://api.fyipe.com';
dashboardUrl = 'https://dashboard.fyipe.com';
domain = 'fyipe.com';
}
}
export const API_URL = apiUrl;
export const DASHBOARD_URL = dashboardUrl;
export const DOMAIN_URL = domain;
export const User = {
getAccessToken() {
return localStorage.getItem('access_token');
},
setAccessToken(token) {
localStorage.setItem('access_token', token);
},
isCardRegistered() {
return localStorage.getItem('cardRegistered');
},
setCardRegistered(value) {
localStorage.setItem('cardRegistered', value);
},
setUserId(id) {
localStorage.setItem('id', id);
},
getUserId() {
return localStorage.getItem('id');
},
getName() {
return localStorage.getItem('name');
},
setName(name) {
localStorage.setItem('name', name);
},
getEmail() {
return localStorage.getItem('email');
},
setEmail(email) {
localStorage.setItem('email', email);
},
initialUrl() {
return sessionStorage.getItem('initialUrl');
},
setProject(project) {
localStorage.setItem('project', project);
},
getProject() {
return localStorage.getItem('project');
},
clear() {
localStorage.clear();
},
removeUserId() {
localStorage.removeItem('id');
},
removeAccessToken() {
localStorage.removeItem('token');
},
isLoggedIn() {
return localStorage.getItem('access_token') ? true : false;
}
};
//Data validation Util goes in here.
export const Validate = {
isDomain(domain) {
return (domain.search(/\./) >= 0);
},
url(url) {
return validUrl.isUri(url);
},
text(text) {
if (!text || text.trim() === '') {
return false;
}
return true;
},
number(number) {
if (number && number.length && !isNaN(number)) {
return true;
}
else {
return false;
}
},
email(email) {
if (this.text(email))
return isEmail(email);
return false;
},
isValidBusinessEmail(email){
return emaildomains.test(email);
},
compare(text1, text2) {
return text1 === text2;
},
card(cardNumber) {
var numberValidation = valid.number(cardNumber);
if (!numberValidation.isPotentiallyValid) {
return false;
}
return true;
},
cardExpiration(expiry) {
var numberValidation = valid.expirationDate(expiry);
if (!numberValidation.isPotentiallyValid) {
return false;
}
return true;
},
cvv(cvv) {
var numberValidation = valid.cvv(cvv);
if (!numberValidation.isPotentiallyValid) {
return false;
}
return true;
},
postalCode(postalCode) {
var numberValidation = valid.postalCode(postalCode);
if (!numberValidation.isPotentiallyValid) {
return false;
}
return true;
}
}
export const PricingPlan = {
getPlans() {
if (window.location.href.indexOf('localhost') > -1 || window.location.href.indexOf('staging') > -1) {
return [
{
category: 'Basic',
planId: 'plan_EgTJMZULfh6THW',
type: 'Month',
amount: 8,
details: '$8 / Month / User'
},
{
category: 'Basic',
planId: 'plan_EgTQAx3Z909Dne',
type: 'Annual',
amount: 80.4,
details: '$80.4 / Year / User'
},
/* {
category: 'Pro',
planId: 'plan_CpIZEEfT4YFSvF',
type: 'month',
amount: 49,
details: '$49 / Month'
},
{
category: 'Pro',
planId: 'plan_CpIZTQWQiIr6rY',
type: 'annual',
amount: 708,
details: '$708 / Year'
},
{
category: 'Pro Plus',
planId: 'plan_CpIatF9qAmeZLP',
type: 'month',
amount: 99,
details: '$99 / Month'
},
{
category: 'Pro Plus',
planId: 'plan_CpIbtqozj1UVGs',
type: 'annual',
amount: 1180,
details: '$1180 / Year'
} */
]
} else {
return [
{
category: 'Basic',
planId: 'plan_EgT8cUrwsxaqCs',
type: 'Month',
amount: 8,
details: '$8 / Month / User'
},
{
category: 'Basic',
planId: 'plan_EgT9hrq9GdIGQ6',
type: 'Annual',
amount: 80.4,
details: '$80.4 / Year / User'
},
/* {
category: 'Pro',
planId: 'plan_CogeidQkPwkycV',
type: 'month',
amount: 49,
details: '$49 / Month'
},
{
category: 'Pro',
planId: 'plan_CogfwRVpqoOLO6',
type: 'annual',
amount: 708,
details: '$708 / Year'
},
{
category: 'Pro Plus',
planId: 'prod_Cogffh2xpitVg6',
type: 'month',
amount: 99,
details: '$99 / Month'
},
{
category: 'Pro Plus',
planId: 'plan_CoggNmls8dUpDy',
type: 'annual',
amount: 1180,
details: '$1180 / Year'
}*/
]
}
},
getPlanById(id) {
let plans = this.getPlans();
if (id) return plans.find(plan => plan.planId === id);
else return plans[0];
},
}
export const tutorials = {
getMonitorTutorials() {
return [
{
id: 's1',
title: 'What are Monitors',
icon: 'bell',
description: <p>You can add web and API server address to
to monitor.<br />It allows you monitor the health status of
your API</p>,
},
{
id: 's2',
title: 'What are Incidents',
icon: 'bell',
description: <p>You can use this feature to acknowledge an incident
that occurred on a monitor<br /> and mark the
incident as resolved after resolving the
issue on your api or server</p>,
},
{
id: 's3',
title: 'Acknowledge/Resolve Incidents',
icon: 'bell',
description: <p>You can use this feature to acknowledge an incident
that occurred on a monitor<br /> and mark the
incident as resolved after resolving the
issue on your api or server</p>,
},
{
id: 's4',
title: 'Status Metrics',
icon: 'bell',
description: <p>Get detailed metrics of all incidents that occurred <br />
on connected monitors and with date and time it was resolved
</p>,
},
{
id: 's5',
title: 'Better Status Handling',
icon: 'bell',
description: <p>After adding monitors for your API, you won&quot;t miss out on any<br />
downtime on your servers, Just let Fyipe alert notify you
</p>,
},
]
}
}
export function getQueryVar(variable, url) {
if (!url) return null;
variable = variable.replace(/[[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + variable + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
export function saveFile(content, filename){
var blob = new Blob([content], {type: 'text/plain;charset=utf-8'});
FileSaver.saveAs(blob, filename);
}

View File

@ -0,0 +1,6 @@
// There are three possible states for our changePassword
// process and we need actions for each of them
export const CHANGEPASSWORD_SUCCESS = 'auth/CHANGEPASSWORD_SUCCESS';
export const CHANGEPASSWORD_FAILED = 'auth/CHANGEPASSWORD_FAILED';
export const CHANGEPASSWORD_REQUEST = 'auth/CHANGEPASSWORD_REQUEST';
export const RESET_CHANGEPASSWORD = 'auth/RESET_CHANGEPASSWORD';

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
export const LOGIN_SUCCESS = 'auth/LOGIN_SUCCESS';
export const LOGIN_FAILED = 'auth/LOGIN_FAILED';
export const LOGIN_REQUEST = 'auth/LOGIN_REQUEST';
export const RESET_LOGIN = 'auth/RESET_LOGIN';

View File

@ -0,0 +1,2 @@
export const OPEN_MODAL = 'OPEN_MODAL';
export const CLOSE_MODAL = 'CLOSE_MODAL';

View File

@ -0,0 +1,17 @@
export const SIGNUP_SUCCESS = 'register/SIGNUP_SUCCESS';
export const SIGNUP_FAILED = 'register/SIGNUP_FAILED';
export const SIGNUP_STEP_INC = 'register/SIGNUP_STEP_INC';
export const SIGNUP_STEP_DEC = 'register/SIGNUP_STEP_DEC';
export const SIGNUP_REQUEST = 'register/SIGNUP_REQUEST';
export const RESET_SIGNUP = 'register/RESET_SIGNUP';
export const SAVE_USER_STATE = 'register/SAVE_USER_STATE';
export const SAVE_CARD_STATE = 'register/SAVE_CARD_STATE';
export const SAVE_COMPANY_STATE = 'register/SAVE_COMPANY_STATE';
export const IS_USER_INVITED_REQUEST = 'register/IS_USER_INVITED_FETCH';
export const IS_USER_INVITED_FAILED = 'register/IS_USER_INVITED_FAILED';
export const IS_USER_INVITED_SUCCESS = 'register/IS_USER_INVITED_SUCCESS';
export const IS_USER_INVITED_RESET = 'register/IS_USER_INVITED_RESET';
export const IS_USER_INVITED_FETCH = 'register/IS_USER_INVITED_FETCH'
export const SKIP_CARD_STEP = 'register/SKIP_CARD_STEP';

View File

@ -0,0 +1,3 @@
export const RESENDTOKEN_SUCCESS = 'auth/RESENDTOKEN_SUCCESS';
export const RESENDTOKEN_FAILED = 'auth/RESENDTOKEN_FAILED';
export const RESENDTOKEN_REQUEST = 'auth/RESENDTOKEN_REQUEST';

View File

@ -0,0 +1,4 @@
export const PASSWORDRESET_SUCCESS = 'auth/PASSWORDRESET_SUCCESS';
export const PASSWORDRESET_FAILED = 'auth/PASSWORDRESET_FAILED';
export const PASSWORDRESET_REQUEST = 'auth/PASSWORDRESET_REQUEST';
export const RESET_PASSWORDRESET = 'auth/RESET_PASSWORDRESET';

View File

@ -0,0 +1,46 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Modal from '../components/Modal';
import { closeModal } from '../actions/modal';
export class Modals extends Component {
render() {
const modals = this.props.modals.map((item, i) => {
const ModalComponent = Modal(item.content);
return (
// Modal(item.content)({
// item,
// zIndex: i,
// key: i,
// onClose: item => this.props.closeModal(item)
// })
<ModalComponent
item={item}
key={i}
zIndex={i}
onClose={item => this.props.closeModal(item)}
/>
)});
return <div id="backboneModals">{modals}</div>;
}
}
Modals.propTypes = {
modals: PropTypes.array.isRequired,
closeModal: PropTypes.func.isRequired
}
Modals.displayName = 'BlackBoneModals'
export default connect(
function mapStateToProps(state) {
return state.modal
},
function mapDispatchToProps(dispatch) {
return bindActionCreators({
closeModal
}, dispatch);
}
)(Modals);

8
accounts/src/errors.js Executable file
View File

@ -0,0 +1,8 @@
export default (error)=>{
switch (error.toString()){
case 'Error: Network Error':
return 'Check your network connection.'
default:
return error
}
}

4
accounts/src/index.css Executable file
View File

@ -0,0 +1,4 @@
body {
overflow: hidden;
height: 100%;
}

32
accounts/src/index.js Executable file
View File

@ -0,0 +1,32 @@
import React from 'react';
import { Provider } from 'react-redux';
import { Frontload } from 'react-frontload';
// import { ConnectedRouter } from 'connected-react-router';
import MixpanelProvider from 'react-mixpanel';
import mixpanel from 'mixpanel-browser';
import * as CB from 'cloudboost';
import ReactGA from 'react-ga';
import ErrorBoundary from './components/basic/ErrorBoundary';
import { render } from 'react-dom';
import store, { history, isServer } from './store';
import App from './App';
import './index.css';
if (!isServer) {
ReactGA.initialize('UA-115085157-1');
CB.CloudApp.init('hcaarmonukbk', 'cdcc37f4-dfc6-44e0-b61b-de8c887ec202');
mixpanel.init('de27af9b37fa926bf648bb704836fd5f');
}
const target = document.getElementById('root');
render (
<Provider store={store} history={history}>
<Frontload noServerRender={true}>
<MixpanelProvider mixpanel={mixpanel}>
<ErrorBoundary>
<App />
</ErrorBoundary>
</MixpanelProvider>
</Frontload>
</Provider>,target
);

View File

@ -0,0 +1,82 @@
import React from 'react';
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import ChangePasswordForm from '../components/auth/ChangePasswordForm';
import { history } from '../store';
class ChangePasswordPage extends React.Component {
constructor(props) {
super(props);
this.props = props;
this.token = this.props.match.params.token;
//if token is not present. Redirect to login page.
if (!this.token) {
history.push('/login');
}
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
render() {
return (
<div id="wrap" style={{ paddingTop: 0 }}>
{/* Header */}
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
{/* RESET PASSWORD BOX */}
<ChangePasswordForm token={this.token} />
<div className="below-box">
<p>
<Link to="/login">
Know your password? <strong>Sign in</strong>.
</Link>
</p>
</div>
{/* END CONTENT */}
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/register">Sign Up</Link>
</li>
<li>
<a href="http://fyipe.com/legal/privacy">Privacy Policy</a>
</li>
<li>
<a href="http://fyipe.com/support">Support</a>
</li>
<li className="last">
<a href="https://hackerbay.io">© HackerBay, Inc.</a>
</li>
</ul>
</div>
</div>
);
}
}
const mapStateToProps = state_Ignored => {
return null;
};
const mapDispatchToProps = dispatch_Ignored => {
return null;
}
ChangePasswordPage.propTypes = {
match: PropTypes.object.isRequired
}
ChangePasswordPage.displayName = 'ChangePasswordPage'
export default connect(mapStateToProps, mapDispatchToProps)(ChangePasswordPage);

98
accounts/src/pages/Login.js Executable file
View File

@ -0,0 +1,98 @@
import React from 'react';
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import LoginForm from '../components/auth/LoginForm';
import { loginUser, loginError } from '../actions/login';
import MessageBox from '../components/MessageBox';
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
submitHandler = (values) => {
let thisObj = this;
this.props.loginUser(values).then((user) => {
if (user && user.data && user.data.id) {
if(window.location.href.indexOf('localhost') <= -1){
thisObj.context.mixpanel.identify(user.data.id);
}
}
})
}
render() {
return (
<div id="wrap">
<div id="header">
<h1>
<a aria-hidden={false} href="/">Fyipe</a>
</h1>
</div>
{/* LOGIN BOX */}
{!this.props.login.success && this.props.login.error ? <MessageBox title={'Your email is not verified.'} message={'An email is on its way to you with new verification link. Please don&apos;t forget to check spam. '}/> :
<LoginForm onSubmit={this.submitHandler} {...this.props} />}
{/* FOOTER */}
<div className="below-box">
<p>
Don&#39;t have an account? <Link to="/register">Sign up</Link>.
</p>
</div>
{/* END FOOTER */}
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/forgot-password">Forgot Password</Link>
</li>
<li>
<a href="http://fyipe.com/legal/privacy">Privacy Policy</a>
</li>
<li>
<a href="http://fyipe.com/support">Support</a>
</li>
<li className="last">
<a href="https://hackerbay.io">© HackerBay, Inc.</a>
</li>
</ul>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
login: state.login
};
};
const mapDispatchToProps = dispatch => bindActionCreators(
{ loginUser, loginError }, dispatch);
LoginPage.propTypes = {
loginUser: PropTypes.func.isRequired,
login: PropTypes.object,
success: PropTypes.bool,
error: PropTypes.oneOfType([
PropTypes.object,
PropTypes.bool,
]),
}
LoginPage.displayName = 'LoginPage'
export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);

89
accounts/src/pages/Register.js Executable file
View File

@ -0,0 +1,89 @@
import React from 'react';
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import RegisterForm from '../components/auth/RegisterForm';
import queryString from 'query-string';
import {PricingPlan} from '../config';
import MessageBox from '../components/MessageBox';
class RegisterPage extends React.Component {
componentWillUnmount() {
document.body.id = '';
document.body.className = '';
}
componentDidMount() {
document.body.id = 'login';
document.body.className = 'register-page';
document.body.style.overflow = 'auto';
}
render() {
this.planId = queryString.parse(this.props.location.search).planId || null;
if(!this.planId){
this.planId = PricingPlan.getPlans()[0].planId;
}
return (
<div id="wrap" style={{ paddingTop: 0 }}>
{/* Header */}
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
{/* REGISTRATION BOX */}
{this.props.register.success ? <MessageBox title="Activate your Fyipe account" message="An email is on its way to you with a verification link. Please don&apos;t forget to check spam. "/> :
<RegisterForm planId={this.planId} location={this.props.location}/>}
{/* END CONTENT */}
<div className="below-box">
<p>
Already have an account? <Link to="/login">Sign in</Link>.
</p>
</div>
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/forgot-password">Forgot Password</Link>
</li>
<li>
<a href="http://fyipe.com/legal/privacy">Privacy Policy</a>
</li>
<li>
<a href="http://fyipe.com/support">Support</a>
</li>
<li className="last">
<a href="https://hackerbay.io">© HackerBay, Inc.</a>
</li>
</ul>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
register: state.register
};
};
const mapDispatchToProps = dispatch_Ignored =>{
return {};
};
RegisterPage.propTypes = {
location: PropTypes.object.isRequired,
register:PropTypes.object,
success:PropTypes.bool,
}
RegisterPage.displayName = 'RegisterPage'
export default connect(mapStateToProps, mapDispatchToProps)(RegisterPage);

164
accounts/src/pages/ResendToken.js Executable file
View File

@ -0,0 +1,164 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../config';
import { FlatLoader } from '../components/basic/Loader';
import { resendToken } from '../actions/resendToken';
import { bindActionCreators } from 'redux';
import { RenderField } from '../components/basic/RenderField';
import { Link } from 'react-router-dom';
import queryString from 'query-string';
import { removeQuery } from '../store';
export class ResendTokenForm extends Component {
state = {
serverResponse: ''
}
submitForm = (values) => {
this.props.resendToken(values);
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
var query = queryString.parse(this.props.location.search).status;
if(query === 'Lc5orxwR5nKxTANs8jfNsCvGD8Us9ltq'){
this.setState({
serverResponse: 'Verification link expired.'
});
}
else if(query === 'eG5aFRDeZXgOkjEfdhOYbFb2lA3Z0OJm'){
this.setState({
serverResponse: 'Invalid Verification link.'
});
}
removeQuery();
}
render() {
const { serverResponse } = this.state;
const { success } = this.props.resendTokenState;
return (
<div id="wrap" style={{ paddingTop: 0 }}>
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
<div id="main-body" className="box css">
<div className="inner">
<form onSubmit={this.props.handleSubmit(this.submitForm)} className="request-reset">
<div className="request-reset-step step" >
<div className="title">
<h2>
{success ? <span>Verification link Sent</span> :
serverResponse ? <span>{serverResponse}</span> :
<span > {this.props.resendTokenState.error ?
<span id="error-msg" className="error" >{this.props.resendTokenState.error}</span>
: 'Resend verification email'} </span>}
</h2>
</div>
<p className="error-message hidden" />
{this.props.resendTokenState.success && <p id="reset-password-success" className="message"> An email is on its way to you with new verification link. Please don&apos;t forget to check spam. </p>}
{!this.props.resendTokenState.success && <p className="message"> Enter your email address below and we will resend you a verification link to activate your fyipe account.</p>}
{!this.props.resendTokenState.success && <div> <p className="text">
<span>
<label htmlFor="email"> Your Email</label>
<Field
component={RenderField}
type="email"
name="email"
id="email"
placeholder="Your Email"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" disabled={this.props.resendTokenState.requesting}>
{!this.props.resendTokenState.requesting && <span>Send Verification Link</span>}
{this.props.resendTokenState.requesting && <FlatLoader />}
</button>
</p> </div>}
</div>
</form>
</div>
</div>
<div className="below-box">
<p>
<Link to="/login">
Know your password? <strong>Sign in</strong>.
</Link>
</p>
</div>
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/register">Sign Up</Link>
</li>
<li>
<a href="http://fyipe.com/legal/privacy">Privacy Policy</a>
</li>
<li>
<a href="http://fyipe.com/support">Support</a>
</li>
<li className="last">
<a href="https://hackerbay.io">© HackerBay, Inc.</a>
</li>
</ul>
</div>
</div>
)
}
}
ResendTokenForm.displayName = 'ResendTokenForm'
function validate(values) {
let errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
return errors;
}
let resendTokenForm = reduxForm({
form: 'resendTokenForm',
validate
})(ResendTokenForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
resendToken
}, dispatch);
};
function mapStateToProps(state) {
return {
resendTokenState: state.resendToken
};
}
ResendTokenForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
resendTokenState: PropTypes.object.isRequired,
resendToken: PropTypes.func.isRequired,
location: PropTypes.object.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(resendTokenForm);

View File

@ -0,0 +1,57 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import ResetPasswordForm from '../components/auth/ResetPasswordForm';
class ResetPasswordPage extends React.Component {
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
render() {
return (
<div id="wrap" style={{ paddingTop: 0 }}>
{/* Header */}
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
{/* RESET PASSWORD BOX */}
<ResetPasswordForm />
<div className="below-box">
<p>
<Link to="/login">
Know your password? <strong>Sign in</strong>.
</Link>
</p>
</div>
{/* END CONTENT */}
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/register">Sign Up</Link>
</li>
<li>
<a href="http://fyipe.com/legal/privacy">Privacy Policy</a>
</li>
<li>
<a href="http://fyipe.com/support">Support</a>
</li>
<li className="last">
<a href="https://hackerbay.io">© HackerBay, Inc.</a>
</li>
</ul>
</div>
</div>
);
}
}
ResetPasswordPage.displayName = 'ResetPasswordPage'
export default connect(null, null)(ResetPasswordPage);

Some files were not shown because too many files have changed in this diff Show More