Lint projects

This commit is contained in:
Jerry Edebua
2020-02-27 14:15:46 +03:00
parent cd00f89467
commit 565edabd6a
1043 changed files with 266817 additions and 236534 deletions

View File

@@ -19,7 +19,6 @@ is referred to as the “Fyipe Software” and a license for Fyipe Software is a
You may not use the Container Image if you do not have a corresponding version and edition of the Fyipe License. Certain restrictions and additional terms may apply, which are described herein. If licensing terms herein conflict with Fyipe License, then this Supplemental License shall govern with respect to the Container Image. BY ACCEPTING THIS SUPPLEMENTAL LICENSE OR USING THE CONTAINER IMAGE, YOU AGREE TO ALL OF THESE TERMS. IF YOU DO NOT ACCEPT AND COMPLY WITH THESE TERMS, YOU MAY NOT USE THE CONTAINER IMAGE.
LICENSE TERMS
Fyipe License. The Fyipe License terms apply to your use of the Container Image and any Fyipe container(s) created with the Container Image which are distinct and separate from a virtual machine.
@@ -32,8 +31,8 @@ ADDITIONAL TERMS
Fyipe Software - When running a Container Image on Client Fyipe Software you may run any number of the Container Image instantiated as Fyipe containers for test or development purposes only. You may not use these Fyipe containers in a production environment.
Third Party Software. The Container Image may include third party applications that are licensed to you under this Supplemental License or under their own terms.
Third Party Software. The Container Image may include third party applications that are licensed to you under this Supplemental License or under their own terms.
Open Source Components. The Container Image may contain third party copyrighted software licensed under open source licenses.
Production Use. You may not use this Fyipe Docker Image or any other Docker Images by Fyipe in production unless you have an active Enterprise Subscription. To request or buy an enterprise subscription or license - please contact our sales team at sales@fyipe.com
Production Use. You may not use this Fyipe Docker Image or any other Docker Images by Fyipe in production unless you have an active Enterprise Subscription. To request or buy an enterprise subscription or license - please contact our sales team at sales@fyipe.com

View File

@@ -1,43 +1,44 @@
# Fyipe
# Fyipe
## Project Architecture
TODO
## Description of the projects in this repo.
- `accounts` - A React project used for Authentication (Log in, Sign up, Forgot Password, etc.)
- `dashboard` - A React project for Fyipe user where user can interact with the Fyipe platform.
- `admin-dashobard` - React Project where admin can block users, delete projects and more.
- `api-docs` - HTML/CSS project. A public reference of Fyipe documentation.
- `backend` - NodeJS Service. It's Fyipe API's.
- `home` - HTML/CSS. Home Page / Marketing page of Fyipe.
- `http-test-server` - A test server used to test website monitors for Fyipe.
- `kubernetes` - yaml files to deploy fyipe on staging, production or any enterprise kubernetes cluster. This also contains DevOps/CI/CD scripts.
- `marketing` - This is where you'll find logos, brief description of Fyipe, etc.
- `certifications` - SOC/ISO/PCI certifications and more.
- `postman-collection` - Postman collection for Fyipe API.
- `probe` - Probe is an agent that gets insalled on a third party server on a thir party datacenter and it monitors users websites, services, from that data center. You can deploy multiple probes to monitor users resources - A probe in a datacenter in EU, in US, etc.
- `server-monitor` - A probe that gets installed on a server and that monitors that particular server.
- `smoke-test` - Smoke test that is executed after Fyipe is deployed to staging or production. If smoke test fails, the staging / production deployment will automatically be rolled back.
- `status-page` - React project - Status page project of Fyipe.
- `zapier` - Fyipe integrates with zapier. This is where integration code is. This gets deployed to zapier directly.
- `init-script` - a container that runs schema migration script.
## Description of the projects in this repo.
## Running this project in local environment.
- `accounts` - A React project used for Authentication (Log in, Sign up, Forgot Password, etc.)
- `dashboard` - A React project for Fyipe user where user can interact with the Fyipe platform.
- `admin-dashobard` - React Project where admin can block users, delete projects and more.
- `api-docs` - HTML/CSS project. A public reference of Fyipe documentation.
- `backend` - NodeJS Service. It's Fyipe API's.
- `home` - HTML/CSS. Home Page / Marketing page of Fyipe.
- `http-test-server` - A test server used to test website monitors for Fyipe.
- `kubernetes` - yaml files to deploy fyipe on staging, production or any enterprise kubernetes cluster. This also contains DevOps/CI/CD scripts.
- `marketing` - This is where you'll find logos, brief description of Fyipe, etc.
- `certifications` - SOC/ISO/PCI certifications and more.
- `postman-collection` - Postman collection for Fyipe API.
- `probe` - Probe is an agent that gets insalled on a third party server on a thir party datacenter and it monitors users websites, services, from that data center. You can deploy multiple probes to monitor users resources - A probe in a datacenter in EU, in US, etc.
- `server-monitor` - A probe that gets installed on a server and that monitors that particular server.
- `smoke-test` - Smoke test that is executed after Fyipe is deployed to staging or production. If smoke test fails, the staging / production deployment will automatically be rolled back.
- `status-page` - React project - Status page project of Fyipe.
- `zapier` - Fyipe integrates with zapier. This is where integration code is. This gets deployed to zapier directly.
- `init-script` - a container that runs schema migration script.
- Before you run this project locally, please make sure you're on Ubuntu or on a Mac machine.
- Install Docker and Docker Compose.
- Install Robomongo / Mongo Compass / or any other MongoDB UI Tool.
- Make sure MongoDB and Redis are NOT running (NO services should run on port 27017 and 6379)
- Run `sudo bash install.sh` - This will take some time (30 mins maybe or more) when you run this for the first time.
- The above command runs the entire project in Docker Compose.
- If you're working on particular sub-project (for ex: accounts, admin-dashboard or literally anything else), your changes will not be reflected in Docker Compose automatically. In this case
- Delete the docker container of the project you're working on. (`sudo docker stop containerId` and `sudo docker rm containerId`)
- Once the container is deleted, cd into that project run `npm install` and `npm run dev`.
- Let other projects / containers run on docker. They will work perfectly fine with a project you're working on.
## Running this project in local environment.
- Before you run this project locally, please make sure you're on Ubuntu or on a Mac machine.
- Install Docker and Docker Compose.
- Install Robomongo / Mongo Compass / or any other MongoDB UI Tool.
- Make sure MongoDB and Redis are NOT running (NO services should run on port 27017 and 6379)
- Run `sudo bash install.sh` - This will take some time (30 mins maybe or more) when you run this for the first time.
- The above command runs the entire project in Docker Compose.
- If you're working on particular sub-project (for ex: accounts, admin-dashboard or literally anything else), your changes will not be reflected in Docker Compose automatically. In this case
- Delete the docker container of the project you're working on. (`sudo docker stop containerId` and `sudo docker rm containerId`)
- Once the container is deleted, cd into that project run `npm install` and `npm run dev`.
- Let other projects / containers run on docker. They will work perfectly fine with a project you're working on.
## LISENCE
Copyright (C) HackerBay, Inc - All Rights Reserved
Unauthorized copying of this project, via any medium is strictly prohibited
This project is proprietary and confidential

View File

@@ -4,10 +4,9 @@ Repository for user authentication of the fyipe dashboard
## Stack
- Reactjs - UI Library
- Redux - State managment
- Redux Forms - Forms
- Reactjs - UI Library
- Redux - State managment
- Redux Forms - Forms
## Start
@@ -33,6 +32,6 @@ In production:
To run puppeteer tests for this repo, follow these steps:
- Start the backend server
- Start the accounts application
- Then run ```npm run test``` from your terminal
- Start the backend server
- Start the accounts application
- Then run `npm run test` from your terminal

View File

@@ -7,34 +7,34 @@ const child_process = require('child_process');
const compression = require('compression');
const env = {
REACT_APP_FYIPE_HOSTED: process.env.IS_SAAS_SERVICE,
REACT_APP_HOST: process.env.HOST,
REACT_APP_DASHBOARD_HOST: process.env.DASHBOARD_HOST,
REACT_APP_BACKEND_HOST: process.env.BACKEND_HOST,
REACT_APP_DOMAIN: process.env.DOMAIN,
REACT_APP_STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
REACT_APP_AMPLITUDE_PUBLIC_KEY: process.env.AMPLITUDE_PUBLIC_KEY
}
REACT_APP_FYIPE_HOSTED: process.env.IS_SAAS_SERVICE,
REACT_APP_HOST: process.env.HOST,
REACT_APP_DASHBOARD_HOST: process.env.DASHBOARD_HOST,
REACT_APP_BACKEND_HOST: process.env.BACKEND_HOST,
REACT_APP_DOMAIN: process.env.DOMAIN,
REACT_APP_STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
REACT_APP_AMPLITUDE_PUBLIC_KEY: process.env.AMPLITUDE_PUBLIC_KEY,
};
fs.writeFileSync('.env', envfile.stringifySync(env));
child_process.execSync('react-env', {
stdio: [0, 1, 2]
stdio: [0, 1, 2],
});
app.use(compression());
app.use(express.static(path.join(__dirname, 'build')));
app.get('/env.js', function (req, res) {
res.sendFile(path.join(__dirname, 'public', 'env.js'));
app.get('/env.js', function(req, res) {
res.sendFile(path.join(__dirname, 'public', 'env.js'));
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
const PORT = 3003
const PORT = 3003;
/* eslint-disable no-console */
console.log(`This project is running on port ${PORT}`)
app.listen(PORT);
console.log(`This project is running on port ${PORT}`);
app.listen(PORT);

View File

@@ -1,53 +1,66 @@
const { fork } = require('child_process')
const { fork } = require('child_process');
const child = fork('./lighthouseWorker');
const Table = require('cli-table');
const program = require('commander');
program
.option('-m, --mobile', 'Run lighthouse on mobile')
.option('-w, --web', 'Run lighthouse on the web');
.option('-m, --mobile', 'Run lighthouse on mobile')
.option('-w, --web', 'Run lighthouse on the web');
program.parse(process.argv);
const table = new Table({
head: ['url', 'performance', 'accessibility', 'best-practices', 'seo'],
style: {head: ['green']},
head: ['url', 'performance', 'accessibility', 'best-practices', 'seo'],
style: { head: ['green'] },
});
const sites = [
'http://localhost:3003/login',
'http://localhost:3003/register',
'http://localhost:3003/forgot-password',
'http://localhost:3003/user-verify/resend',
'http://localhost:3003/change-password/wrongtoken',
'http://localhost:3003/login',
'http://localhost:3003/register',
'http://localhost:3003/forgot-password',
'http://localhost:3003/user-verify/resend',
'http://localhost:3003/change-password/wrongtoken',
];
let sitesIndex = 0;
let checksFailed = false;
child.on('message', function (score){
const scores = [sites[sitesIndex - 1], score.performance, score.accessibility, score.bestPractices, score.seo];
table.push(scores);
if (score.performance < 50 || score.accessibility < 80 || score.bestPractices < 80 || score.seo < 80) {
checksFailed = true;
}
if (sitesIndex < sites.length) {
pages();
} else {
process.stdout.write(table.toString());
process.stdout.write('\n');
if (checksFailed) {
process.stderr.write('Error: Some scores are below 80 please check table above.\n')
process.exit(1);
}
process.exit();
}
child.on('message', function(score) {
const scores = [
sites[sitesIndex - 1],
score.performance,
score.accessibility,
score.bestPractices,
score.seo,
];
table.push(scores);
if (
score.performance < 50 ||
score.accessibility < 80 ||
score.bestPractices < 80 ||
score.seo < 80
) {
checksFailed = true;
}
if (sitesIndex < sites.length) {
pages();
} else {
process.stdout.write(table.toString());
process.stdout.write('\n');
if (checksFailed) {
process.stderr.write(
'Error: Some scores are below 80 please check table above.\n'
);
process.exit(1);
}
process.exit();
}
});
function pages () {
if (program.mobile) {
child.send({url: sites[sitesIndex], mobile: program.mobile });
} else {
child.send({url: sites[sitesIndex], mobile: false });
}
sitesIndex++
function pages() {
if (program.mobile) {
child.send({ url: sites[sitesIndex], mobile: program.mobile });
} else {
child.send({ url: sites[sitesIndex], mobile: false });
}
sitesIndex++;
}
pages();

View File

@@ -3,53 +3,65 @@ const chromeLauncher = require('chrome-launcher');
const ora = require('ora');
function launchChromeAndRunLighthouse(url, flags = {}, config = null) {
return chromeLauncher.launch(flags).then(chrome => {
flags.port = chrome.port;
return lighthouse(url, flags, config).then(results => {
return chrome.kill().then(() => results)
});
});
return chromeLauncher.launch(flags).then(chrome => {
flags.port = chrome.port;
return lighthouse(url, flags, config).then(results => {
return chrome.kill().then(() => results);
});
});
}
const flags = {chromeFlags: ['--headless'], emulatedFormFactor: 'desktop'};
const flags = { chromeFlags: ['--headless'], emulatedFormFactor: 'desktop' };
process.on('message', function (data) {
if (data.mobile) flags.emulatedFormFactor = 'mobile';
const scores = {};
const spinner = ora(`Running lighthouse on ${data.url}`).start();
spinner.color = 'green';
launchChromeAndRunLighthouse(data.url, flags).then(results => {
results.artifacts = 'ignore';
results.reportGroups = 'ignore';
results.timing = 'ignore';
results.userAgent = 'ignore';
results.lighthouseVersion = 'ignore';
results.runWarnings = 'runWarnings';
results.report = 'ignore';
results.runtimeConfig = 'ignore';
results.lhr.userAgent = 'ignore';
results.lhr.environment = 'ignore';
results.lhr.configSettings = 'ignore';
results.lhr.metrics = 'ignore';
results.lhr.audits = 'ignore';
results.lhr.categoryGroups = 'ignore';
scores.performance = Math.ceil(results.lhr.categories.performance.score * 100);
scores.accessibility = Math.ceil(results.lhr.categories.accessibility.score * 100);
scores.bestPractices = Math.ceil(results.lhr.categories['best-practices'].score * 100);
scores.seo = Math.ceil(results.lhr.categories.seo.score * 100);
if (scores.performance < 50 || scores.accessibility < 80 || scores.bestPractices < 80 || scores.seo < 80) {
spinner.fail();
} else {
spinner.succeed();
}
process.send(scores);
return scores;
})
.catch(err => {
/* eslint-disable no-console */
console.log(err)
process.exit(1);
});
process.on('message', function(data) {
if (data.mobile) flags.emulatedFormFactor = 'mobile';
const scores = {};
const spinner = ora(`Running lighthouse on ${data.url}`).start();
spinner.color = 'green';
launchChromeAndRunLighthouse(data.url, flags)
.then(results => {
results.artifacts = 'ignore';
results.reportGroups = 'ignore';
results.timing = 'ignore';
results.userAgent = 'ignore';
results.lighthouseVersion = 'ignore';
results.runWarnings = 'runWarnings';
results.report = 'ignore';
results.runtimeConfig = 'ignore';
results.lhr.userAgent = 'ignore';
results.lhr.environment = 'ignore';
results.lhr.configSettings = 'ignore';
results.lhr.metrics = 'ignore';
results.lhr.audits = 'ignore';
results.lhr.categoryGroups = 'ignore';
scores.performance = Math.ceil(
results.lhr.categories.performance.score * 100
);
scores.accessibility = Math.ceil(
results.lhr.categories.accessibility.score * 100
);
scores.bestPractices = Math.ceil(
results.lhr.categories['best-practices'].score * 100
);
scores.seo = Math.ceil(results.lhr.categories.seo.score * 100);
if (
scores.performance < 50 ||
scores.accessibility < 80 ||
scores.bestPractices < 80 ||
scores.seo < 80
) {
spinner.fail();
} else {
spinner.succeed();
}
process.send(scores);
return scores;
})
.catch(err => {
/* eslint-disable no-console */
console.log(err);
process.exit(1);
});
});

39600
accounts/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,91 +1,91 @@
{
"name": "fyipe-accounts",
"version": "3.0.1891",
"private": true,
"homepage": "/",
"dependencies": {
"@beam-australia/react-env": "^2.1.2",
"amplitude-js": "^5.8.0",
"axios": "^0.18.0",
"browserslist": "^4.6.1",
"card-validator": "^4.3.0",
"cli-table": "^0.3.1",
"compression": "^1.7.4",
"envfile": "^3.0.0",
"express": "^4.16.4",
"faker": "^4.1.0",
"file-saver": "^2.0.1",
"history": "^4.7.2",
"jest": "^24.7.1",
"loadable-components": "^2.2.3",
"prop-types": "^15.6.1",
"puppeteer": "^1.19.0",
"query-string": "^5.1.1",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-frontload": "^1.0.3",
"react-ga": "^2.5.3",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
"react-scripts": "^3.0.1",
"react-stripe-elements": "^1.6.0",
"redux": "^3.7.2",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0",
"sane-email-validation": "^1.1.0",
"should": "^13.2.3",
"universal-cookie": "^4.0.0",
"valid-url": "^1.0.9"
},
"scripts": {
"lint": "eslint .",
"fix-lint": "eslint . --fix",
"dev": "PORT=3003 react-scripts start",
"build": "react-scripts build && npm run build-sw && npm run clean-cra-sw",
"clean-cra-sw": "rm -f build/precache-manifest.*.js && rm -f build/service-worker.js",
"test": "jest --runInBand src/test",
"start": "node index.js",
"audit": "npm-audit-ci-wrapper --threshold=high",
"light-house": "node lighthouse.js --web",
"light-house-mobile": "node lighthouse.js --mobile",
"build-sw": "node ./src/sw-build.js",
"dep-check": "depcheck ./ --skip-missing=true --ignores='eslint,babel-*,browserslist,loadable-components,@beam-australia/react-env'"
},
"devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"chrome-launcher": "^0.12.0",
"commander": "^4.0.1",
"depcheck": "^0.9.2",
"eslint-plugin-react": "^7.18.3",
"lighthouse": "^5.6.0",
"npm-audit-ci-wrapper": "^2.4.3",
"ora": "^4.0.3",
"redux-logger": "^3.0.6",
"workbox-build": "^4.3.1"
},
"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"
]
}
"name": "fyipe-accounts",
"version": "3.0.1891",
"private": true,
"homepage": "/",
"dependencies": {
"@beam-australia/react-env": "^2.1.2",
"amplitude-js": "^5.8.0",
"axios": "^0.18.0",
"browserslist": "^4.6.1",
"card-validator": "^4.3.0",
"cli-table": "^0.3.1",
"compression": "^1.7.4",
"envfile": "^3.0.0",
"express": "^4.16.4",
"faker": "^4.1.0",
"file-saver": "^2.0.1",
"history": "^4.7.2",
"jest": "^24.7.1",
"loadable-components": "^2.2.3",
"prop-types": "^15.6.1",
"puppeteer": "^1.19.0",
"query-string": "^5.1.1",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-frontload": "^1.0.3",
"react-ga": "^2.5.3",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
"react-scripts": "^3.0.1",
"react-stripe-elements": "^1.6.0",
"redux": "^3.7.2",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0",
"sane-email-validation": "^1.1.0",
"should": "^13.2.3",
"universal-cookie": "^4.0.0",
"valid-url": "^1.0.9"
},
"scripts": {
"lint": "eslint .",
"fix-lint": "eslint . --fix",
"dev": "PORT=3003 react-scripts start",
"build": "react-scripts build && npm run build-sw && npm run clean-cra-sw",
"clean-cra-sw": "rm -f build/precache-manifest.*.js && rm -f build/service-worker.js",
"test": "jest --runInBand src/test",
"start": "node index.js",
"audit": "npm-audit-ci-wrapper --threshold=high",
"light-house": "node lighthouse.js --web",
"light-house-mobile": "node lighthouse.js --mobile",
"build-sw": "node ./src/sw-build.js",
"dep-check": "depcheck ./ --skip-missing=true --ignores='eslint,babel-*,browserslist,loadable-components,@beam-australia/react-env'"
},
"devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"chrome-launcher": "^0.12.0",
"commander": "^4.0.1",
"depcheck": "^0.9.2",
"eslint-plugin-react": "^7.18.3",
"lighthouse": "^5.6.0",
"npm-audit-ci-wrapper": "^2.4.3",
"ora": "^4.0.3",
"redux-logger": "^3.0.6",
"workbox-build": "^4.3.1"
},
"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

@@ -11,76 +11,76 @@ import ReactGA from 'react-ga';
import Cookies from 'universal-cookie';
import { saveStatusPage } from './actions/login';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
const cookies = new Cookies();
const logoutData = cookies.get('logoutData');
if (!isServer) {
history.listen(location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
});
history.listen(location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
});
}
const statusPageLogin = queryString.parse(window.location.search).statusPage;
const statusPageURL = queryString.parse(window.location.search).statusPageURL;
if (logoutData && User.isLoggedIn()) {
cookies.remove('logoutData', { domain: DOMAIN_URL });
localStorage.clear();
cookies.remove('logoutData', { domain: DOMAIN_URL });
localStorage.clear();
} else if (!statusPageLogin && !logoutData && User.isLoggedIn()) {
window.location = DASHBOARD_URL;
window.location = DASHBOARD_URL;
}
const App = (props) => {
if (statusPageLogin && statusPageURL) {
props.saveStatusPage({
statusPageLogin,
statusPageURL
})
}
const App = props => {
if (statusPageLogin && statusPageURL) {
props.saveStatusPage({
statusPageLogin,
statusPageURL,
});
}
return (<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>
);
}
return (
<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';
App.propTypes = {
saveStatusPage: PropTypes.func.isRequired,
}
saveStatusPage: PropTypes.func.isRequired,
};
function mapStateToProps(state) {
return state.login;
return state.login;
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ saveStatusPage }, dispatch)
return bindActionCreators({ saveStatusPage }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);

View File

@@ -1,61 +1,57 @@
import {
postApi
} from '../api';
import * as types from '../constants/changePassword'
import errors from '../errors'
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
};
return {
type: types.CHANGEPASSWORD_REQUEST,
payload: promise,
};
}
export function changePasswordError(error) {
return {
type: types.CHANGEPASSWORD_FAILED,
payload: error
};
return {
type: types.CHANGEPASSWORD_FAILED,
payload: error,
};
}
export function changePasswordSuccess(values) {
return {
type: types.CHANGEPASSWORD_SUCCESS,
payload: values
};
return {
type: types.CHANGEPASSWORD_SUCCESS,
payload: values,
};
}
export const resetChangePassword = () => {
return {
type: types.RESET_CHANGEPASSWORD,
};
return {
type: types.RESET_CHANGEPASSWORD,
};
};
// Calls the API to register a user.
export function changePassword(values) {
return function (dispatch) {
return function(dispatch) {
const promise = postApi('user/reset-password', values);
dispatch(changePasswordRequest(promise));
const 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)));
});
};
}
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)));
}
);
};
}

View File

@@ -1,10 +1,12 @@
import { postApi } from '../api';
import * as types from '../constants/login';
import {
postApi
} from '../api';
import * as types from '../constants/login'
import { User, DASHBOARD_URL, DOMAIN_URL, ADMIN_DASHBOARD_URL } from '../config.js';
import errors from '../errors'
User,
DASHBOARD_URL,
DOMAIN_URL,
ADMIN_DASHBOARD_URL,
} from '../config.js';
import errors from '../errors';
import { getQueryVar } from '../config';
import { resendToken } from './resendToken';
import Cookies from 'universal-cookie';
@@ -14,205 +16,219 @@ import store from '../store';
// process and we need actions for each of them
export function loginRequest(promise) {
return {
type: types.LOGIN_REQUEST,
payload: promise
};
return {
type: types.LOGIN_REQUEST,
payload: promise,
};
}
export function loginError(error) {
return {
type: types.LOGIN_FAILED,
payload: error
};
return {
type: types.LOGIN_FAILED,
payload: error,
};
}
export function loginSuccess(user) {
//save user session details.
if (!user.id) {
User.setEmail(user.email)
return {
type: types.LOGIN_SUCCESS,
payload: user,
};
}
//save user session details.
if (!user.id) {
User.setEmail(user.email);
return {
type: types.LOGIN_SUCCESS,
payload: user,
};
}
const state = store.getState();
const { statusPageLogin, statusPageURL } = state.login;
if (statusPageLogin) {
const newURL = `${statusPageURL}?userId=${user.id}&accessToken=${user.tokens.jwtAccessToken}`;
return window.location = newURL;
}
User.setUserId(user.id);
User.setAccessToken(user.tokens.jwtAccessToken);
User.setEmail(user.email);
User.setName(user.name);
User.setCardRegistered(user.cardRegistered);
const state = store.getState();
const { statusPageLogin, statusPageURL } = state.login;
if (statusPageLogin) {
const newURL = `${statusPageURL}?userId=${user.id}&accessToken=${user.tokens.jwtAccessToken}`;
return (window.location = newURL);
}
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
let cookies = new Cookies();
let userData = user;
cookies.set('data', userData, { path: '/', maxAge: 30, domain: DOMAIN_URL });
//share localStorage with dashboard app
let cookies = new Cookies();
let userData = user;
cookies.set('data', userData, {
path: '/',
maxAge: 30,
domain: DOMAIN_URL,
});
if(user.role === 'master-admin'){
//share localStorage with admin dashboard app
cookies = new Cookies();
userData = user;
cookies.set('admin-data', userData, { path: '/', maxAge: 30, domain: DOMAIN_URL });
}
if (user.role === 'master-admin') {
//share localStorage with admin dashboard app
cookies = new Cookies();
userData = user;
cookies.set('admin-data', userData, {
path: '/',
maxAge: 30,
domain: DOMAIN_URL,
});
}
if (user.redirect){
return window.location = `${user.redirect}?accessToken=${user.tokens.jwtAccessToken}`;
}else if(user.role === 'master-admin'){
window.location = ADMIN_DASHBOARD_URL
}else{
window.location = DASHBOARD_URL
}
return {
type: types.LOGIN_SUCCESS,
payload: user
};
if (user.redirect) {
return (window.location = `${user.redirect}?accessToken=${user.tokens.jwtAccessToken}`);
} else if (user.role === 'master-admin') {
window.location = ADMIN_DASHBOARD_URL;
} else {
window.location = DASHBOARD_URL;
}
return {
type: types.LOGIN_SUCCESS,
payload: user,
};
}
export const resetLogin = () => {
return {
type: types.RESET_LOGIN,
};
return {
type: types.RESET_LOGIN,
};
};
export function verifyTokenRequest(promise) {
return {
type: types.AUTH_VERIFICATION_REQUEST,
payload: promise
};
return {
type: types.AUTH_VERIFICATION_REQUEST,
payload: promise,
};
}
export function verifyTokenError(error) {
return {
type: types.AUTH_VERIFICATION_FAILED,
payload: error
};
return {
type: types.AUTH_VERIFICATION_FAILED,
payload: error,
};
}
// Calls the API to register a user.
export function loginUser(values) {
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if(redirect) values.redirect = redirect;
return function (dispatch) {
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if (redirect) values.redirect = redirect;
return function(dispatch) {
const promise = postApi('user/login', values);
dispatch(loginRequest(promise));
const promise = postApi('user/login', values);
dispatch(loginRequest(promise));
promise.then(function (user) {
dispatch(loginSuccess(user.data));
}, function (error) {
if(error.message === 'Verify your email first.'){
dispatch(resendToken(values));
}
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;
};
promise.then(
function(user) {
dispatch(loginSuccess(user.data));
},
function(error) {
if (error.message === 'Verify your email first.') {
dispatch(resendToken(values));
}
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;
};
}
// Calls the API to verify a user token and log them in.
export function verifyAuthToken(values) {
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if(redirect) values.redirect = redirect;
const email = User.getEmail();
values.email = email;
return function (dispatch) {
const promise = postApi('user/totp/verifyToken', values);
dispatch(verifyTokenRequest(promise));
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if (redirect) values.redirect = redirect;
const email = User.getEmail();
values.email = email;
return function(dispatch) {
const promise = postApi('user/totp/verifyToken', values);
dispatch(verifyTokenRequest(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(verifyTokenError(errors(error)));
});
return 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(verifyTokenError(errors(error)));
}
);
return promise;
};
}
// Use backup code to login a user.
export const resetBackupCodeLogin = () => {
return {
type: types.RESET_BACKUP_CODE_VERIFICATION,
};
return {
type: types.RESET_BACKUP_CODE_VERIFICATION,
};
};
export function useBackupCodeRequest(promise) {
return {
type: types.BACKUP_CODE_VERIFICATION_REQUEST,
payload: promise
};
return {
type: types.BACKUP_CODE_VERIFICATION_REQUEST,
payload: promise,
};
}
export function useBackupCodeError(error) {
return {
type: types.BACKUP_CODE_VERIFICATION_FAILED,
payload: error
};
return {
type: types.BACKUP_CODE_VERIFICATION_FAILED,
payload: error,
};
}
export function verifyBackupCode(values) {
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if(redirect) values.redirect = redirect;
const email = User.getEmail();
values.email = email;
return function (dispatch) {
const promise = postApi('user/verify/backupCode', values);
dispatch(useBackupCodeRequest(promise));
const initialUrl = User.initialUrl();
const redirect = getQueryVar('redirectTo', initialUrl);
if (redirect) values.redirect = redirect;
const email = User.getEmail();
values.email = email;
return function(dispatch) {
const promise = postApi('user/verify/backupCode', values);
dispatch(useBackupCodeRequest(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(useBackupCodeError(errors(error)));
});
return 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(useBackupCodeError(errors(error)));
}
);
return promise;
};
}
export function saveStatusPage(data) {
return {
type: types.SAVE_STATUS_PAGE,
payload: data
};
}
return {
type: types.SAVE_STATUS_PAGE,
payload: data,
};
}

View File

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

View File

@@ -1,229 +1,226 @@
import {
postApi
} from '../api';
import * as types from '../constants/register'
import errors from '../errors'
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
};
return {
type: types.SIGNUP_FAILED,
payload: error,
};
}
export function saveUserState(values) {
return {
type: types.SAVE_USER_STATE,
payload: values
};
return {
type: types.SAVE_USER_STATE,
payload: values,
};
}
export function savePlanId(planId) {
return {
type: types.SAVE_PLAN_ID,
payload: planId
};
return {
type: types.SAVE_PLAN_ID,
payload: planId,
};
}
export function saveCardState(values) {
return {
type: types.SAVE_CARD_STATE,
payload: values
};
return {
type: types.SAVE_CARD_STATE,
payload: values,
};
}
export function saveCompanyState(values) {
return {
type: types.SAVE_COMPANY_STATE,
payload: values
};
return {
type: types.SAVE_COMPANY_STATE,
payload: values,
};
}
export function signUpRequest(promise) {
return {
type: types.SIGNUP_REQUEST,
payload: promise
};
return {
type: types.SIGNUP_REQUEST,
payload: promise,
};
}
export function signUpReset() {
return {
type: types.RESET_SIGNUP,
};
return {
type: types.RESET_SIGNUP,
};
}
export function signupSuccess(user) {
return {
type: types.SIGNUP_SUCCESS,
payload: user
}
return {
type: types.SIGNUP_SUCCESS,
payload: user,
};
}
export const resetSignup = () => {
return {
type: types.RESET_SIGNUP,
};
return {
type: types.RESET_SIGNUP,
};
};
// Calls the API to register a user.
export function signupUser(values) {
return function (dispatch) {
const 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;
};
return function(dispatch) {
const 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,
};
return {
type: types.SIGNUP_STEP_INC,
};
};
//np payload for inc and dec action creators.
export const skipCardStep = () => {
return {
type: types.SKIP_CARD_STEP,
};
return {
type: types.SKIP_CARD_STEP,
};
};
export const decrementStep = () => {
return {
type: types.SIGNUP_STEP_DEC,
};
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
};
return {
type: types.IS_USER_INVITED_REQUEST,
payload: promise,
};
}
export function isUserInvitedReset() {
return {
type: types.IS_USER_INVITED_RESET,
};
return {
type: types.IS_USER_INVITED_RESET,
};
}
export function isUserInvitedError(error) {
return {
type: types.IS_USER_INVITED_RESET,
payload: error
};
return {
type: types.IS_USER_INVITED_RESET,
payload: error,
};
}
export function isUserInvitedSuccess(data) {
return {
type: types.IS_USER_INVITED_SUCCESS,
payload: data
};
return {
type: types.IS_USER_INVITED_SUCCESS,
payload: data,
};
}
export const resetIsUserInvited = () => {
return {
type: types.IS_USER_INVITED_RESET,
};
return {
type: types.IS_USER_INVITED_RESET,
};
};
// Calls the API to register a user.
export function isUserInvited(values) {
return function (dispatch) {
const 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 function(dispatch) {
const 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;
};
return promise;
};
}
export function addCardRequest(promise) {
return {
type: types.ADD_CARD_REQUEST,
payload: promise
};
return {
type: types.ADD_CARD_REQUEST,
payload: promise,
};
}
export function addCardFailed(error) {
return {
type: types.ADD_CARD_FAILED,
payload: error
};
return {
type: types.ADD_CARD_FAILED,
payload: error,
};
}
export function addCardSuccess(card) {
return {
type: types.ADD_CARD_SUCCESS,
payload: card
};
return {
type: types.ADD_CARD_SUCCESS,
payload: card,
};
}
export function addCard(data) {
return function(dispatch) {
const promise = postApi('stripe/checkCard', data);
return function (dispatch) {
const promise = postApi('stripe/checkCard', data)
dispatch(addCardRequest(promise));
dispatch(addCardRequest(promise));
promise.then(function (card) {
dispatch(addCardSuccess(card.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(addCardFailed(error));
});
return promise;
}
}
promise.then(
function(card) {
dispatch(addCardSuccess(card.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(addCardFailed(error));
}
);
return promise;
};
}

View File

@@ -1,51 +1,50 @@
import { postApi } from '../api';
import * as types from '../constants/resendToken'
import errors from '../errors'
import * as types from '../constants/resendToken';
import errors from '../errors';
export function resendTokenRequest(promise) {
return {
type: types.RESENDTOKEN_REQUEST,
payload: promise
};
return {
type: types.RESENDTOKEN_REQUEST,
payload: promise,
};
}
export function resendTokenError(error) {
return {
type: types.RESENDTOKEN_FAILED,
payload: error
};
return {
type: types.RESENDTOKEN_FAILED,
payload: error,
};
}
export function resendTokenSuccess(data) {
return {
type: types.RESENDTOKEN_SUCCESS,
payload: data
};
return {
type: types.RESENDTOKEN_SUCCESS,
payload: data,
};
}
export function resendToken(values) {
return function(dispatch){
return function(dispatch) {
const promise = postApi('user/resend', values);
dispatch(resendTokenRequest(promise));
const 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)));
});
};
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

@@ -1,60 +1,59 @@
import { postApi } from '../api';
import * as types from '../constants/resetPassword'
import errors from '../errors'
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
};
return {
type: types.PASSWORDRESET_REQUEST,
payload: promise,
};
}
export function resetPasswordError(error) {
return {
type: types.PASSWORDRESET_FAILED,
payload: error
};
return {
type: types.PASSWORDRESET_FAILED,
payload: error,
};
}
export function resetPasswordSuccess(data) {
return {
type: types.PASSWORDRESET_SUCCESS,
payload: data
};
return {
type: types.PASSWORDRESET_SUCCESS,
payload: data,
};
}
export const resetResetPassword = () => {
return {
type: types.RESET_PASSWORDRESET,
};
return {
type: types.RESET_PASSWORDRESET,
};
};
export function resetPassword(values) {
return function(dispatch){
return function(dispatch) {
const promise = postApi('user/forgot-password', values);
dispatch(resetPasswordRequest(promise));
const 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)));
});
};
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)));
}
);
};
}

View File

@@ -3,15 +3,15 @@ const { env } = require('./config');
amplitude.init(env('AMPLITUDE_PUBLIC_KEY'), null, { includeReferrer: true });
export const setUserId = function (userId) {
export const setUserId = function(userId) {
amplitude.setUserId(userId);
};
export const identify = function(userId) {
amplitude.identify(userId);
}
};
export const setUserProperties = function(properties) {
amplitude.setUserProperties(properties);
}
export const logEvent = function (event, data) {
};
export const logEvent = function(event, data) {
amplitude.logEvent(event, data);
};
};

View File

@@ -1,10 +1,6 @@
import axios from 'axios';
import {
API_URL
} from './config';
import {
User
} from './config';
import { API_URL } from './config';
import { User } from './config';
import { history } from './store';
const baseURL = API_URL;
@@ -12,27 +8,25 @@ const Q = require('q');
const headers = {
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
Accept: 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
};
export function postApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'POST',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -49,17 +43,17 @@ export function postApi(url, data) {
export function getApi(url) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'GET',
url: `${baseURL}/${url}`,
headers
headers,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -75,21 +69,20 @@ export function getApi(url) {
return deffered.promise;
}
export function putApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'PUT',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -107,18 +100,18 @@ export function putApi(url, data) {
export function deleteApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'DELETE',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');

View File

@@ -1,35 +1,40 @@
import React, { Component, Fragment } from 'react';
class NotFound extends Component {
render() {
return (
<Fragment>
<div className="db-World-root" >
<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
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'
NotFound.displayName = 'NotFound';
export default NotFound;

View File

@@ -1,15 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types'
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="request-reset-step step">
<div className="title">
<h2 style={{ marginBottom: 0 }}>
{props.title}
</h2>
<h2 style={{ marginBottom: 0 }}>{props.title}</h2>
</div>
<p className="message">
{props.message}
@@ -18,13 +16,13 @@ export default function MessageBox(props) {
</div>
</div>
</div>
)
);
}
MessageBox.displayName = 'MessageBox'
MessageBox.displayName = 'MessageBox';
MessageBox.propTypes = {
title: PropTypes.string,
message: PropTypes.string,
children: PropTypes.node
}
children: PropTypes.node,
};

View File

@@ -1,43 +1,49 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
const composableComponent = (ComposedComponent) => {
const composableComponent = ComposedComponent => {
class Modal extends Component {
constructor(props){
constructor(props) {
super(props);
this.props = props;
this.onClose = this.onClose.bind(this);
this.onConfirm = this.onConfirm.bind(this);
}
onClose =(value)=> {
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)=> {
};
onConfirm = value => {
const _this = this;
if (this.props.item.onConfirm) {
this.props.item.onConfirm(value)
.then(() => _this.props.onClose(_this.props.item),
()=> {})
this.props.item.onConfirm(value).then(
() => _this.props.onClose(_this.props.item),
() => {}
);
} else {
this.props.onClose(this.props.item)
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'};
const modalContainerStyle = {
overflowX: 'auto',
overflowY: 'scroll',
display: 'block',
top: '0px',
};
return (
<div
className={mainClass}
style={{
zIndex: (zIndex + 1) * 10000
zIndex: (zIndex + 1) * 10000,
}}
>
<div
@@ -47,12 +53,17 @@ const composableComponent = (ComposedComponent) => {
opacity: 1,
transform: 'none',
display: 'block',
pointerEvents: 'auto'
pointerEvents: 'auto',
}}
>
<div className="modal_container" style={modalContainerStyle}>
<ComposedComponent closeThisDialog={this.onClose} confirmThisDialog={this.onConfirm} />
<div
className="modal_container"
style={modalContainerStyle}
>
<ComposedComponent
closeThisDialog={this.onClose}
confirmThisDialog={this.onConfirm}
/>
</div>
</div>
</div>
@@ -62,15 +73,14 @@ const composableComponent = (ComposedComponent) => {
Modal.propTypes = {
onConfirm: PropTypes.func,
item: PropTypes.object.isRequired,
onClose:PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
extraClasses: PropTypes.string,
zIndex: PropTypes.number.isRequired
}
zIndex: PropTypes.number.isRequired,
};
Modal.displayName = 'Modal'
Modal.displayName = 'Modal';
return Modal;
}
};
export default composableComponent;
export default composableComponent;

File diff suppressed because it is too large Load Diff

View File

@@ -1,132 +1,179 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../../config';
import { ButtonSpinner } from '../basic/Loader.js';
import { changePasswordError, changePasswordSuccess, changePassword, resetChangePassword } from '../../actions/changePassword';
import {
changePasswordError,
changePasswordSuccess,
changePassword,
resetChangePassword,
} from '../../actions/changePassword';
import { bindActionCreators } from 'redux';
import { RenderField } from '../basic/RenderField';
import { Link } from 'react-router-dom'
import { Link } from 'react-router-dom';
const errorStyle = {
color: '#c23d4b'
}
color: '#c23d4b',
};
export class ChangePasswordForm extends Component {
submitForm = values => {
values.token = this.props.token || '';
this.props.changePassword(values);
};
submitForm =(values)=> {
values.token = this.props.token || '';
this.props.changePassword(values);
}
render() {
const changePasswordStateError = this.props.changePasswordState.error;
let header;
if (changePasswordStateError) {
header = <span style={errorStyle}>{changePasswordStateError}</span>;
} else {
header = <span>Reset Password</span>;
}
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">
<div className="title">
<h2>{header}</h2>
</div>
render() {
const changePasswordStateError = this.props.changePasswordState.error;
let header;
if (changePasswordStateError) {
header = <span style={errorStyle}>{changePasswordStateError}</span>
} else {
header = <span>Reset Password</span>
}
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" >
<div className="title">
<h2>
{header}
</h2>
</div>
<p className="error-message hidden" />
<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">
{' '}
Please enter a new password to continue
</p>
)}
{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"> Please enter a new password to continue</p>}
{!this.props.changePasswordState.success && <div> <p className="text">
<span id="passwordField">
<label htmlFor="password"> New Password </label>
<Field
component={RenderField}
type="password"
name="password"
id="password"
placeholder="Password"
/>
</span>
</p>
<p className="text">
<span id="confirmPasswordField">
<label htmlFor="confirmPassword"> Confirm New 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 && <ButtonSpinner />}
</button>
</p> </div>}
{!this.props.changePasswordState.success && (
<div>
{' '}
<p className="text">
<span id="passwordField">
<label htmlFor="password">
{' '}
New Password{' '}
</label>
<Field
component={RenderField}
type="password"
name="password"
id="password"
placeholder="Password"
/>
</span>
</p>
<p className="text">
<span id="confirmPasswordField">
<label htmlFor="confirmPassword">
{' '}
Confirm New 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 && (
<ButtonSpinner />
)}
</button>
</p>{' '}
</div>
)}
</div>
</form>
</div>
</div>
</form>
</div>
</div>
)
}
);
}
}
ChangePasswordForm.displayName = 'ChangePasswordForm'
ChangePasswordForm.displayName = 'ChangePasswordForm';
function validate(values) {
const errors = {};
if (!Validate.text(values.password)) {
errors.password = 'Password is required.'
}
if (Validate.text(values.password) && !Validate.isStrongPassword(values.password)) {
errors.password = 'Password should be atleast 8 characters long'
}
if (!Validate.text(values.confirmPassword)) {
errors.confirmPassword = 'Confirm Password is required.';
}
if (!Validate.compare(values.password, values.confirmPassword)) {
errors.confirmPassword = 'Password and confirm password should match.';
}
return errors;
const errors = {};
if (!Validate.text(values.password)) {
errors.password = 'Password is required.';
}
if (
Validate.text(values.password) &&
!Validate.isStrongPassword(values.password)
) {
errors.password = 'Password should be atleast 8 characters long';
}
if (!Validate.text(values.confirmPassword)) {
errors.confirmPassword = 'Confirm Password is required.';
}
if (!Validate.compare(values.password, values.confirmPassword)) {
errors.confirmPassword = 'Password and confirm password should match.';
}
return errors;
}
const changePasswordForm = reduxForm({
form: 'changePasswordForm', // a unique identifier for this form
validate
form: 'changePasswordForm', // a unique identifier for this form
validate,
})(ChangePasswordForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
changePasswordError, changePasswordSuccess, changePassword, resetChangePassword
}, dispatch);
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
changePasswordError,
changePasswordSuccess,
changePassword,
resetChangePassword,
},
dispatch
);
};
function mapStateToProps(state) {
return {
changePasswordState: state.changePassword
};
return {
changePasswordState: state.changePassword,
};
}
ChangePasswordForm.propTypes = {
changePassword: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
changePasswordState: PropTypes.object.isRequired,
token: PropTypes.any
}
changePassword: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
changePasswordState: PropTypes.object.isRequired,
token: PropTypes.any,
};
export default connect(mapStateToProps, mapDispatchToProps)(changePasswordForm);

View File

@@ -1,182 +1,209 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
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';
import { RenderField } from '../basic/RenderField';
import { Validate } from '../../config';
import { FlatLoader } from '../basic/Loader.js';
const errorStyle = {
color:'red'
}
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>
)
}
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'
CompanyForm.displayName = 'CompanyForm';
const validate = function(values){
const error = {};
const validate = function(values) {
const error = {};
if(!Validate.text(values.companyName)){
error.companyName = 'Company name is required.'
}
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.companyRole)) {
error.companyRole = 'Job Title is required.';
}
if(!Validate.text(values.companyPhoneNumber)){
error.companyPhoneNumber ='Phone Number 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.comapnySize)) {
error.comapnySize = 'Phone Number is required.';
}
if(!Validate.text(values.reference)){
error.reference ='This is required.'
}
return error;
}
if (!Validate.text(values.reference)) {
error.reference = 'This is required.';
}
return error;
};
const companyForm = reduxForm({
form: 'CompanyForm', // <------ same form name
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true,
validate // <------ unregister fields on unmoun
form: 'CompanyForm', // <------ same form name
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true,
validate, // <------ unregister fields on unmoun
})(CompanyForm);
const mapDispatchToProps = (dispatch_Ignored) => {
return {
}
}
const mapDispatchToProps = dispatch_Ignored => {
return {};
};
function mapStateToProps(state) {
return {
register: state.register
};
return {
register: state.register,
};
}
CompanyForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
submitForm: PropTypes.func.isRequired
}
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
submitForm: PropTypes.func.isRequired,
};
export default connect(mapStateToProps, mapDispatchToProps)(companyForm);

View File

@@ -1,152 +1,166 @@
import React, { Component } from 'react'
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 { ButtonSpinner } from '../basic/Loader.js';
import { loginError, loginSuccess, loginUser, resetLogin } from '../../actions/login';
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';
const errorStyle = {
color: '#c23d4b'
}
color: '#c23d4b',
};
export class LoginForm extends Component {
state = {
serverResponse: '',
};
state = {
serverResponse: ''
}
componentDidMount() {
const query = queryString.parse(this.props.location.search).status;
let 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;
const loginError = this.props.login.error;
let header;
if (loginError) {
header = <span style={errorStyle}>{loginError}</span>;
} else if (serverResponse) {
header = <span>{serverResponse}</span>;
} else {
header = <span>Welcome back!</span>;
}
componentDidMount() {
const query = queryString.parse(this.props.location.search).status;
let 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;
const loginError = this.props.login.error;
let header;
if (loginError) {
header = <span style={errorStyle}>{loginError}</span>
}
else if (serverResponse) {
header = <span>{serverResponse}</span>
} else {
header = <span>Welcome back!</span>
}
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>{header}</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>
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>
{header}
</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</span>}
{this.props.login.requesting && <ButtonSpinner />}
</button>
</p>
</div>
</form>
</div>
</div>
</div>
)
}
<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</span>
)}
{this.props.login.requesting && (
<ButtonSpinner />
)}
</button>
</p>
</div>
</form>
</div>
</div>
</div>
);
}
}
LoginForm.displayName = 'LoginForm'
LoginForm.displayName = 'LoginForm';
const validate = function (values) {
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
const 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.';
}
}
else {
if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
}
if (!Validate.text(values.password)) {
errors.password = 'Password is required.';
}
if (!Validate.text(values.password)) {
errors.password = 'Password is required.'
}
return errors;
}
return errors;
};
const loginForm = reduxForm({
form: 'LoginForm', // a unique identifier for this form
validate,
destroyOnUnmount: false
form: 'LoginForm', // a unique identifier for this form
validate,
destroyOnUnmount: false,
})(LoginForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
loginError, loginSuccess, loginUser, resetLogin
}, dispatch);
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
loginError,
loginSuccess,
loginUser,
resetLogin,
},
dispatch
);
};
function mapStateToProps(state) {
return {
login: state.login
};
return {
login: state.login,
};
}
LoginForm.propTypes = {
onSubmit: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
login: PropTypes.object.isRequired,
location: PropTypes.object.isRequired
}
onSubmit: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
login: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
};
export default connect(mapStateToProps, mapDispatchToProps)(loginForm);

View File

@@ -1,101 +1,135 @@
import React, { Component } from 'react'
import { reduxForm } from 'redux-form'
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import UserForm from './UserForm';
import CardForm from './CardForm';
import { connect } from 'react-redux';
import { signupUser, incrementStep, decrementStep, saveUserState, isUserInvited } from '../../actions/register'
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import { setUserId, setUserProperties, identify, logEvent } from '../../analytics';
import { IS_DEV } from '../../config';
export class RegisterForm extends Component {
constructor(props) {
super(props);
this.props = props;
}
userFormSubmitted = (values) => {
const 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 (!IS_DEV) {
setUserId(user.data.id);
identify(user.data.id);
setUserProperties({
'Name': user.data.name,
'Created': new Date(),
'Email': user.data.email
});
logEvent('Sign up completed for invited user', { 'First Time': 'TRUE', 'id': user.data.id });
}
}
})
} else {
thisObj.props.incrementStep();
if (!IS_DEV) {
setUserId(values.email);
identify(values.email);
setUserProperties({
'Name': values.name,
'Created': new Date(),
'Email': values.email,
'CompanyName': values.companyName,
'CompanyPhoneNumber': values.companyPhoneNumber
});
logEvent('Sign up step one completed', { 'First Time': 'TRUE' });
}
}
}, function (error) {
return error
});
}
render() {
const { step } = this.props.register;
return (
<div>
{ step === 1 && <UserForm submitForm={this.userFormSubmitted} error={this.props.register.error} location={this.props.location} />}
{ step === 2 && <CardForm planId={this.props.planId} error={this.props.register.error} />}
</div>
)
}
}
RegisterForm.displayName = 'RegisterForm';
const registerForm = reduxForm({
form: 'RegisterForm'
})(RegisterForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
import {
signupUser,
incrementStep,
decrementStep,
saveUserState,
isUserInvited,
}, dispatch);
} from '../../actions/register';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import {
setUserId,
setUserProperties,
identify,
logEvent,
} from '../../analytics';
import { IS_DEV } from '../../config';
export class RegisterForm extends Component {
constructor(props) {
super(props);
this.props = props;
}
userFormSubmitted = values => {
const 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 (!IS_DEV) {
setUserId(user.data.id);
identify(user.data.id);
setUserProperties({
Name: user.data.name,
Created: new Date(),
Email: user.data.email,
});
logEvent(
'Sign up completed for invited user',
{
'First Time': 'TRUE',
id: user.data.id,
}
);
}
}
});
} else {
thisObj.props.incrementStep();
if (!IS_DEV) {
setUserId(values.email);
identify(values.email);
setUserProperties({
Name: values.name,
Created: new Date(),
Email: values.email,
CompanyName: values.companyName,
CompanyPhoneNumber: values.companyPhoneNumber,
});
logEvent('Sign up step one completed', {
'First Time': 'TRUE',
});
}
}
},
function(error) {
return error;
}
);
};
render() {
const { step } = this.props.register;
return (
<div>
{step === 1 && (
<UserForm
submitForm={this.userFormSubmitted}
error={this.props.register.error}
location={this.props.location}
/>
)}
{step === 2 && (
<CardForm
planId={this.props.planId}
error={this.props.register.error}
/>
)}
</div>
);
}
}
RegisterForm.displayName = 'RegisterForm';
const registerForm = reduxForm({
form: 'RegisterForm',
})(RegisterForm);
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
signupUser,
incrementStep,
decrementStep,
saveUserState,
isUserInvited,
},
dispatch
);
};
function mapStateToProps(state) {
return {
register: state.register
};
return {
register: state.register,
};
}
RegisterForm.propTypes = {
saveUserState: PropTypes.func.isRequired,
isUserInvited: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
planId: PropTypes.string.isRequired,
location: PropTypes.object.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

@@ -1,113 +1,156 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../../config';
import { ButtonSpinner } from '../basic/Loader.js';
import { resetPasswordError, resetPasswordSuccess, resetPassword, resetResetPassword } from '../../actions/resetPassword';
import {
resetPasswordError,
resetPasswordSuccess,
resetPassword,
resetResetPassword,
} from '../../actions/resetPassword';
import { bindActionCreators } from 'redux';
import { RenderField } from '../basic/RenderField';
const errorStyle = {
color: '#c23d4b'
}
color: '#c23d4b',
};
export class ResetPasswordForm extends Component {
submitForm = values => {
this.props.resetPassword(values);
};
submitForm = (values) => {
this.props.resetPassword(values);
}
render() {
const resetPasswordError = this.props.resetPasswordState.error;
let header;
if (resetPasswordError) {
header = <span style={errorStyle} id="error-msg">{resetPasswordError}</span>
} else {
header = <span>Reset Password.</span>
}
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" >
<div className="title">
<h2>
{header}
</h2>
</div>
{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"
/>
render() {
const resetPasswordError = this.props.resetPasswordState.error;
let header;
if (resetPasswordError) {
header = (
<span style={errorStyle} id="error-msg">
{resetPasswordError}
</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 && <ButtonSpinner />}
</button>
</p> </div>}
);
} else {
header = <span>Reset Password.</span>;
}
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">
<div className="title">
<h2>{header}</h2>
</div>
{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 && (
<ButtonSpinner />
)}
</button>
</p>{' '}
</div>
)}
</div>
</form>
</div>
</div>
</form>
</div>
</div>
)
}
);
}
}
ResetPasswordForm.displayName = 'ResetPasswordForm'
ResetPasswordForm.displayName = 'ResetPasswordForm';
function validate(values) {
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
return errors;
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.';
} else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.';
}
return errors;
}
const resetPasswordForm = reduxForm({
form: 'resetPasswordForm', // a unique identifier for this form
validate
form: 'resetPasswordForm', // a unique identifier for this form
validate,
})(ResetPasswordForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
resetPasswordError, resetPasswordSuccess, resetPassword, resetResetPassword
}, dispatch);
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
resetPasswordError,
resetPasswordSuccess,
resetPassword,
resetResetPassword,
},
dispatch
);
};
function mapStateToProps(state) {
return {
resetPasswordState: state.resetPassword
};
return {
resetPasswordState: state.resetPassword,
};
}
ResetPasswordForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
resetPasswordState: PropTypes.object.isRequired,
resetPassword: PropTypes.func.isRequired
}
handleSubmit: PropTypes.func.isRequired,
resetPasswordState: PropTypes.object.isRequired,
resetPassword: PropTypes.func.isRequired,
};
export default connect(mapStateToProps, mapDispatchToProps)(resetPasswordForm);
export default connect(mapStateToProps, mapDispatchToProps)(resetPasswordForm);

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
@@ -12,223 +12,351 @@ import { logEvent } from '../../analytics';
import { IS_DEV } from '../../config';
class UserForm extends Component {
state = {
serverResponse: '',
};
state = {
serverResponse: ''
}
componentDidMount() {
const query = queryString.parse(this.props.location.search).status;
if (query === 'z1hb0g8vfg0rWM1Ly1euQSZ1L5ZNHuAk') {
this.setState({
serverResponse: 'No user found for this token'
});
}
removeQuery();
}
componentDidMount() {
const query = queryString.parse(this.props.location.search).status;
if (query === 'z1hb0g8vfg0rWM1Ly1euQSZ1L5ZNHuAk') {
this.setState({
serverResponse: 'No user found for this token',
});
}
removeQuery();
}
trackClick = (target) => {
const { formValues } = this.props;
const allowedValues = ['email', 'name', 'companyName', 'companyPhoneNumber'];
const filteredValues = formValues && Object.keys(formValues)
.filter(key => allowedValues.includes(key))
.reduce((obj, key) => {
obj[key] = formValues[key];
return obj;
}, {});
trackClick = target => {
const { formValues } = this.props;
const allowedValues = [
'email',
'name',
'companyName',
'companyPhoneNumber',
];
const filteredValues =
formValues &&
Object.keys(formValues)
.filter(key => allowedValues.includes(key))
.reduce((obj, key) => {
obj[key] = formValues[key];
return obj;
}, {});
if (!IS_DEV) {
logEvent(`Register page click on # ${target.id}`, { data: filteredValues});
}
}
if (!IS_DEV) {
logEvent(`Register page click on # ${target.id}`, {
data: filteredValues,
});
}
};
render() {
const { serverResponse } = this.state;
return (
<div id="main-body" className="box css" style={{ width: 500 }} onClick={(event) => this.trackClick(event.target)}>
<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)}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<p className="text" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<span id="email">
<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" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<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>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<p className="text" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<span>
<label htmlFor="companyName">Company Name</label>
<Field
type="text"
name="companyName"
id="companyName"
component={RenderField}
placeholder="Company Name"
/>
</span>
</p>
<p className="text" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<span>
<label htmlFor="companyPhoneNumber">Phone Number</label>
<Field
type="text"
component={RenderField}
name="companyPhoneNumber"
id="companyPhoneNumber"
placeholder="+1-123-456-7890"
/>
</span>
</p>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<p className="text" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<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" style={{ display: 'block', maxWidth: '50%', marginTop: 0 }}>
<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" style={{ width: '100%', maxWidth: '100%' }}>
<button style={{ width: '100%' }} 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 ) ? <ButtonSpinner /> : <span>Sign Up</span>}
</button>
</p>
</form>
</div>
</div>
)
}
render() {
const { serverResponse } = this.state;
return (
<div
id="main-body"
className="box css"
style={{ width: 500 }}
onClick={event => this.trackClick(event.target)}
>
<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
)}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
<p
className="text"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<span id="email">
<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"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<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>
</div>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
<p
className="text"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<span>
<label htmlFor="companyName">
Company Name
</label>
<Field
type="text"
name="companyName"
id="companyName"
component={RenderField}
placeholder="Company Name"
/>
</span>
</p>
<p
className="text"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<span>
<label htmlFor="companyPhoneNumber">
Phone Number
</label>
<Field
type="text"
component={RenderField}
name="companyPhoneNumber"
id="companyPhoneNumber"
placeholder="+1-123-456-7890"
/>
</span>
</p>
</div>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
<p
className="text"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<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"
style={{
display: 'block',
maxWidth: '50%',
marginTop: 0,
}}
>
<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"
style={{ width: '100%', maxWidth: '100%' }}
>
<button
style={{ width: '100%' }}
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) ? (
<ButtonSpinner />
) : (
<span>Sign Up</span>
)}
</button>
</p>
</form>
</div>
</div>
);
}
}
UserForm.displayName = 'UserForm'
UserForm.displayName = 'UserForm';
const validate = function (values) {
const error = {};
const validate = function(values) {
const error = {};
if (!Validate.text(values.name))
error.name = 'Name is required.';
if (!Validate.text(values.name)) error.name = 'Name is required.';
if(Validate.text(values.name) && !Validate.isValidName(values.name))
error.name = 'Name is not valid.';
if (Validate.text(values.name) && !Validate.isValidName(values.name))
error.name = 'Name is not valid.';
if (!Validate.text(values.email))
error.email = 'Email 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.email) && !Validate.email(values.email))
error.email = 'Email is not valid.';
if (!Validate.text(values.companyName))
error.companyName = 'Company name is required.';
if (
!Validate.isValidBusinessEmail(values.email) &&
Validate.email(values.email)
)
error.email = 'Please enter a business email address.';
if (!Validate.text(values.companyPhoneNumber))
error.companyPhoneNumber = 'Phone number is required.';
if (!Validate.text(values.companyName))
error.companyName = 'Company name is required.';
if (Validate.text(values.companyPhoneNumber) && !Validate.isValidNumber(values.companyPhoneNumber))
error.companyPhoneNumber = 'Phone number is invalid.';
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.password) && !Validate.isStrongPassword(values.password)) {
error.password = 'Password should be atleast 8 characters long'
}
if (
Validate.text(values.companyPhoneNumber) &&
!Validate.isValidNumber(values.companyPhoneNumber)
)
error.companyPhoneNumber = 'Phone number is invalid.';
if (!Validate.text(values.confirmPassword))
error.confirmPassword = 'Confirm Password is required.';
if (!Validate.text(values.password))
error.password = 'Password is required.';
if (
Validate.text(values.password) &&
!Validate.isStrongPassword(values.password)
) {
error.password = 'Password should be atleast 8 characters long';
}
if (!Validate.compare(values.password, values.confirmPassword)) {
error.confirmPassword = 'Password and confirm password should match.';
}
if (!Validate.text(values.confirmPassword))
error.confirmPassword = 'Confirm Password is required.';
return error;
if (!Validate.compare(values.password, values.confirmPassword)) {
error.confirmPassword = 'Password and confirm password should match.';
}
}
return error;
};
const userForm = reduxForm({
form: 'UserSignupForm', // <------ same form name
destroyOnUnmount: false,
validate
form: 'UserSignupForm', // <------ same form name
destroyOnUnmount: false,
validate,
})(UserForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
}, dispatch);
}
const mapDispatchToProps = dispatch => {
return bindActionCreators({}, dispatch);
};
function mapStateToProps(state) {
return {
register: state.register,
formValues: state.form && state.form.UserSignupForm && state.form.UserSignupForm.values
};
return {
register: state.register,
formValues:
state.form &&
state.form.UserSignupForm &&
state.form.UserSignupForm.values,
};
}
UserForm.propTypes = {
submitForm: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
formValues: PropTypes.object
}
submitForm: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
register: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
formValues: PropTypes.object,
};
export default connect(mapStateToProps, mapDispatchToProps)(userForm);

View File

@@ -3,5 +3,5 @@ export const companySize = [
{ name: '11-50', code: '11-50' },
{ name: '51-200', code: '51-200' },
{ name: '200-1000', code: '200-1000' },
{ name: '1000+', code: '1000+' }
];
{ name: '1000+', code: '1000+' },
];

View File

@@ -1,32 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { companySize } from './CompanySizeList';
const errorStyle = {
color: 'red',
topMargin: '5px'
}
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>
)
<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.displayName = 'CompanySizeSelector';
CompanySizeSelector.propTypes = {
meta: PropTypes.object.isRequired,
input: PropTypes.object.isRequired,
id: PropTypes.string
}
meta: PropTypes.object.isRequired,
input: PropTypes.object.isRequired,
id: PropTypes.string,
};
export default CompanySizeSelector
export default CompanySizeSelector;

View File

@@ -52,7 +52,7 @@ export const countries = [
{ 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: "Cote d'Ivoire", code: 'CI' },
{ name: 'Croatia', code: 'HR' },
{ name: 'Cuba', code: 'CU' },
{ name: 'Cyprus', code: 'CY' },
@@ -114,11 +114,11 @@ export const countries = [
{ name: 'Kazakhstan', code: 'KZ' },
{ name: 'Kenya', code: 'KE' },
{ name: 'Kiribati', code: 'KI' },
{ name: 'Korea, Democratic People\'s Republic of', code: 'KP' },
{ 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: "Lao People's Democratic Republic", code: 'LA' },
{ name: 'Latvia', code: 'LV' },
{ name: 'Lebanon', code: 'LB' },
{ name: 'Lesotho', code: 'LS' },
@@ -241,5 +241,5 @@ export const countries = [
{ name: 'Western Sahara', code: 'EH' },
{ name: 'Yemen', code: 'YE' },
{ name: 'Zambia', code: 'ZM' },
{ name: 'Zimbabwe', code: 'ZW' }
{ name: 'Zimbabwe', code: 'ZW' },
];

View File

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

View File

@@ -4,41 +4,57 @@ import { logEvent } from '../../analytics';
import { IS_DEV } from '../../config';
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 (!IS_DEV) {
logEvent('Error', { error, info });
}
} catch (error) {
return error
constructor(props) {
super(props);
this.state = { hasError: false };
}
}
render() {
if (this.state.hasError) {
return (
<div id="app-loading" style={{ 'position': 'fixed', 'top': '0', 'bottom': '0', 'left': '0', 'right': '0', 'backgroundColor': '#fdfdfd', 'zIndex': '999', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center' }}>
<div>An unexpected error has occured. Please reload the page to continue</div>
</div>
)
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
try {
if (!IS_DEV) {
logEvent('Error', { 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: '#fdfdfd',
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;
}
return this.props.children;
}
}
ErrorBoundary.displayName = 'ErrorBoundary';
ErrorBoundary.propTypes = {
children: PropTypes.any
}
children: PropTypes.any,
};
export default ErrorBoundary;
export default ErrorBoundary;

View File

@@ -1,25 +1,63 @@
import React from 'react';
const loaderStyle = {
backgroundColor: '#96d8ff'
}
backgroundColor: '#96d8ff',
};
export const FlatLoader = () => (<div className="ball-pulse"><div style={loaderStyle}></div><div style={loaderStyle}></div><div style={loaderStyle}></div></div>);
export const FlatLoader = () => (
<div className="ball-pulse">
<div style={loaderStyle}></div>
<div style={loaderStyle}></div>
<div style={loaderStyle}></div>
</div>
);
FlatLoader.displayName = 'FlatLoader'
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>);
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'
FormLoader.displayName = 'FormLoader';
export const ListLoader = () => (<div className="ball-beat" style={{ textAlign: 'center', marginTop: '20px' }}><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div></div>);
export const ListLoader = () => (
<div
className="ball-beat"
style={{ textAlign: 'center', marginTop: '20px' }}
>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
</div>
);
ListLoader.displayName = 'ListLoader'
ListLoader.displayName = 'ListLoader';
export const TeamListLoader = () => (<div className="ball-beat" style={{ textAlign: 'center',width:'95px'}}><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div><div style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}></div></div>);
export const TeamListLoader = () => (
<div className="ball-beat" style={{ textAlign: 'center', width: '95px' }}>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
<div
style={{ height: '8px', width: '8px', backgroundColor: '#4c4c4c' }}
></div>
</div>
);
TeamListLoader.displayName = 'TeamListLoader'
TeamListLoader.displayName = 'TeamListLoader';
export const Spinner = () => (
<div className="Spinner bs-SpinnerLegacy Spinner--color--white Box-root Flex-inlineFlex Flex-alignItems--center Flex-justifyContent--center">
@@ -37,17 +75,20 @@ export const Spinner = () => (
/>
</svg>
</div>
)
);
Spinner.displayName = 'Spinner'
Spinner.displayName = 'Spinner';
export const ButtonSpinner = () => (
<div className="Spinner bs-SpinnerLegacy Spinner--color--white Box-root Flex-inlineFlex Flex-alignItems--center Flex-justifyContent--center" style={{ marginTop: 4 }}>
<div
className="Spinner bs-SpinnerLegacy Spinner--color--white Box-root Flex-inlineFlex Flex-alignItems--center Flex-justifyContent--center"
style={{ marginTop: 4 }}
>
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="Spinner-svg"
style={{ width: 25, height: 25 }}
className="Spinner-svg"
style={{ width: 25, height: 25 }}
>
<ellipse
cx={12}
@@ -58,49 +99,49 @@ export const ButtonSpinner = () => (
/>
</svg>
</div>
)
ButtonSpinner.displayName = 'ButtonSpinner'
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'
ButtonSpinner.displayName = 'ButtonSpinner';
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

@@ -1,13 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
const errorStyle = {
color:'#c23d4b',
width: '222px'
}
const RenderField = ({ input, placeholder, type, meta, className, id, disabled, initialValue, style }) => (
color: '#c23d4b',
width: '222px',
};
const RenderField = ({
input,
placeholder,
type,
meta,
className,
id,
disabled,
initialValue,
style,
}) => (
<span>
<span>
<input
@@ -21,21 +30,16 @@ const RenderField = ({ input, placeholder, type, meta, className, id, disabled,
style={style || {}}
/>
</span>
{meta.error &&
meta.touched &&
<span style={errorStyle}>
{meta.error}
</span>}
{meta.error && meta.touched && (
<span style={errorStyle}>{meta.error}</span>
)}
</span>
)
);
RenderField.displayName = 'RenderField'
RenderField.displayName = 'RenderField';
RenderField.propTypes = {
initialValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
]),
initialValue: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
input: PropTypes.object.isRequired,
placeholder: PropTypes.string,
type: PropTypes.string.isRequired,
@@ -44,10 +48,7 @@ RenderField.propTypes = {
meta: PropTypes.object.isRequired,
rows: PropTypes.string,
disabled: PropTypes.bool,
style: PropTypes.object
}
export {RenderField}
style: PropTypes.object,
};
export { RenderField };

View File

@@ -14,7 +14,10 @@ let developmentEnv = false;
export function env(value) {
const { _env } = window;
return (_env && _env[`REACT_APP_${value}`]) || process.env[`REACT_APP_${value}`];
return (
(_env && _env[`REACT_APP_${value}`]) ||
process.env[`REACT_APP_${value}`]
);
}
if (!isServer) {
@@ -24,18 +27,19 @@ if (!isServer) {
domain = 'localhost';
adminDashboardUrl = 'http://localhost:3100';
developmentEnv = true;
}
else if (env('BACKEND_HOST')) {
} else if (env('BACKEND_HOST')) {
apiUrl = env('BACKEND_HOST');
dashboardUrl = env('DASHBOARD_HOST');
domain = env('DOMAIN');
if (apiUrl.indexOf('staging') > -1 || apiUrl.indexOf('app.local') > -1) {
if (
apiUrl.indexOf('staging') > -1 ||
apiUrl.indexOf('app.local') > -1
) {
developmentEnv = true;
}
}
}
export const API_URL = apiUrl;
export const DASHBOARD_URL = dashboardUrl;
@@ -47,7 +51,6 @@ export const ADMIN_DASHBOARD_URL = adminDashboardUrl;
export const IS_DEV = developmentEnv;
export const User = {
getAccessToken() {
return localStorage.getItem('access_token');
},
@@ -112,15 +115,13 @@ export const User = {
isLoggedIn() {
return localStorage.getItem('access_token') ? true : false;
}
},
};
//Data validation Util goes in here.
export const Validate = {
isDomain(domain) {
return (domain.search(/\./) >= 0);
return domain.search(/\./) >= 0;
},
url(url) {
@@ -128,7 +129,6 @@ export const Validate = {
},
text(text) {
if (!text || text.trim() === '') {
return false;
}
@@ -137,37 +137,34 @@ export const Validate = {
},
number(number) {
if (number && number.length && !isNaN(number)) {
return true;
}
else {
} else {
return false;
}
},
isValidNumber(number) {
// eslint-disable-next-line
if(number.match('^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$')) {
if (number.match('^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-s./0-9]*$')) {
return true;
}
return false;
},
isStrongPassword(password) {
if(password.match('^(?=.{8,})')) {
if (password.match('^(?=.{8,})')) {
return true;
}
return false;
},
email(email) {
if (this.text(email))
return isEmail(email);
if (this.text(email)) return isEmail(email);
return false;
},
isValidBusinessEmail(email){
isValidBusinessEmail(email) {
return emaildomains.test(email);
},
@@ -215,36 +212,38 @@ export const Validate = {
return true;
},
isValidName(name) {
isValidName(name) {
// eslint-disable-next-line
if(name.match('[A-Z][a-zA-Z][^#&<>\"~;$^%{}?]{1,20}$')) {
return true
if (name.match('[A-Z][a-zA-Z][^#&<>"~;$^%{}?]{1,20}$')) {
return true;
}
return false;
}
}
},
};
export const PricingPlan = {
getPlans() {
if (window.location.href.indexOf('localhost') > -1 || window.location.href.indexOf('staging') > -1 || window.location.href.indexOf('app.local') > -1) {
if (
window.location.href.indexOf('localhost') > -1 ||
window.location.href.indexOf('staging') > -1 ||
window.location.href.indexOf('app.local') > -1
) {
return [
{
category: 'Basic',
planId: 'plan_EgTJMZULfh6THW',
type: 'month',
amount: 8,
details: '$8 / Month / User'
details: '$8 / Month / User',
},
{
category: 'Basic',
planId: 'plan_EgTQAx3Z909Dne',
type: 'annual',
amount: 80.4,
details: '$80.4 / Year / User'
details: '$80.4 / Year / User',
},
/* {
/* {
category: 'Pro',
planId: 'plan_CpIZEEfT4YFSvF',
type: 'month',
@@ -272,7 +271,7 @@ export const PricingPlan = {
amount: 1180,
details: '$1180 / Year'
} */
]
];
} else {
return [
{
@@ -280,16 +279,16 @@ export const PricingPlan = {
planId: 'plan_EgT8cUrwsxaqCs',
type: 'month',
amount: 8,
details: '$8 / Month / User'
details: '$8 / Month / User',
},
{
category: 'Basic',
planId: 'plan_EgT9hrq9GdIGQ6',
type: 'annual',
amount: 80.4,
details: '$80.4 / Year / User'
details: '$80.4 / Year / User',
},
/* {
/* {
category: 'Pro',
planId: 'plan_CogeidQkPwkycV',
type: 'month',
@@ -317,7 +316,7 @@ export const PricingPlan = {
amount: 1180,
details: '$1180 / Year'
}*/
]
];
}
},
@@ -326,57 +325,79 @@ export const PricingPlan = {
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>,
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>,
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>,
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>,
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&apos;t miss out on any<br />
downtime on your servers, Just let Fyipe alert notify you
</p>,
description: (
<p>
After adding monitors for your API, you won&apos;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;
@@ -388,7 +409,7 @@ export function getQueryVar(variable, url) {
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
export function saveFile(content, filename){
const blob = new Blob([content], {type: 'text/plain;charset=utf-8'});
export function saveFile(content, filename) {
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
FileSaver.saveAs(blob, filename);
}
}

View File

@@ -3,4 +3,4 @@
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';
export const RESET_CHANGEPASSWORD = 'auth/RESET_CHANGEPASSWORD';

File diff suppressed because one or more lines are too long

View File

@@ -11,7 +11,11 @@ export const AUTH_VERIFICATION_REQUEST = 'auth/AUTH_VERIFICATION_REQUEST';
export const RESET_AUTH_VERIFICATION = 'auth/RESET_AUTH_VERIFICATION';
// Use backup code for logging in a user
export const BACKUP_CODE_VERIFICATION_SUCCESS = 'auth/BACKUP_CODE_VERIFICATION_SUCCESS';
export const BACKUP_CODE_VERIFICATION_FAILED = 'auth/BACKUP_CODE_VERIFICATION_FAILED';
export const BACKUP_CODE_VERIFICATION_REQUEST = 'auth/BACKUP_CODE_VERIFICATION_REQUEST';
export const RESET_BACKUP_CODE_VERIFICATION = 'auth/RESET_BACKUP_CODE_VERIFICATION';
export const BACKUP_CODE_VERIFICATION_SUCCESS =
'auth/BACKUP_CODE_VERIFICATION_SUCCESS';
export const BACKUP_CODE_VERIFICATION_FAILED =
'auth/BACKUP_CODE_VERIFICATION_FAILED';
export const BACKUP_CODE_VERIFICATION_REQUEST =
'auth/BACKUP_CODE_VERIFICATION_REQUEST';
export const RESET_BACKUP_CODE_VERIFICATION =
'auth/RESET_BACKUP_CODE_VERIFICATION';

View File

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

View File

@@ -12,7 +12,7 @@ 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 IS_USER_INVITED_FETCH = 'register/IS_USER_INVITED_FETCH';
export const SKIP_CARD_STEP = 'register/SKIP_CARD_STEP';
@@ -20,4 +20,4 @@ export const ADD_CARD_SUCCESS = 'ADD_CARD_SUCCESS';
export const ADD_CARD_FAILED = 'ADD_CARD_FAILED';
export const ADD_CARD_REQUEST = 'ADD_CARD_REQUEST';
export const SAVE_PLAN_ID= 'SAVE_PLAN_ID';
export const SAVE_PLAN_ID = 'SAVE_PLAN_ID';

View File

@@ -1,4 +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';
export const RESET_PASSWORDRESET = 'auth/RESET_PASSWORDRESET';

View File

@@ -1,46 +1,50 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
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>;
}
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: PropTypes.array.isRequired,
closeModal: PropTypes.func.isRequired,
};
Modals.displayName = 'BlackBoneModals'
Modals.displayName = 'BlackBoneModals';
export default connect(
function mapStateToProps(state) {
return state.modal
},
function mapDispatchToProps(dispatch) {
return bindActionCreators({
closeModal
}, dispatch);
}
)(Modals);
function mapStateToProps(state) {
return state.modal;
},
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
closeModal,
},
dispatch
);
}
)(Modals);

View File

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

View File

@@ -1,5 +1,5 @@
body {
overflow: hidden;
height: 100%;
background-color: #f7f7f7
overflow: hidden;
height: 100%;
background-color: #f7f7f7;
}

View File

@@ -10,18 +10,19 @@ import './index.css';
import * as serviceWorker from './serviceWorker';
if (!isServer) {
ReactGA.initialize('UA-115085157-1');
ReactGA.initialize('UA-115085157-1');
}
const target = document.getElementById('root');
render (
<Provider store={store} history={history}>
<Frontload noServerRender={true}>
<ErrorBoundary>
<App />
</ErrorBoundary>
</Frontload>
</Provider>,target
render(
<Provider store={store} history={history}>
<Frontload noServerRender={true}>
<ErrorBoundary>
<App />
</ErrorBoundary>
</Frontload>
</Provider>,
target
);
// this will enable the app to work offline and load faster

View File

@@ -1,82 +1,82 @@
import React from 'react';
import PropTypes from 'prop-types'
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;
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');
}
}
//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';
}
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>
);
}
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;
return null;
};
const mapDispatchToProps = dispatch_Ignored => {
return null;
}
return null;
};
ChangePasswordPage.propTypes = {
match: PropTypes.object.isRequired
}
match: PropTypes.object.isRequired,
};
ChangePasswordPage.displayName = 'ChangePasswordPage'
ChangePasswordPage.displayName = 'ChangePasswordPage';
export default connect(mapStateToProps, mapDispatchToProps)(ChangePasswordPage);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
@@ -11,112 +11,118 @@ import { IS_DEV } from '../config';
import { history } from '../store';
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
constructor(props) {
super(props);
this.props = props;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
submitHandler = values => {
this.props.loginUser(values).then(user => {
if (user && user.data && user.data.id) {
if (!IS_DEV) {
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id });
}
}
});
};
submitHandler = (values) => {
this.props.loginUser(values).then((user) => {
if (user && user.data && user.data.id) {
if(!IS_DEV){
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id })
}
}
})
}
render() {
const { login } = this.props;
render() {
const { login } = this.props;
if (login.success && !login.user.tokens) {
history.push('/user-auth/token');
}
if (login.success && !login.user.tokens) {
history.push('/user-auth/token');
}
return (
<div id="wrap">
<div id="header">
<h1>
<a aria-hidden={false} href="/">
Fyipe
</a>
</h1>
</div>
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 &&
this.props.login.error === 'Verify your email first.' ? (
<div>
<MessageBox
title="Your email is not verified."
//eslint-disable-next-line
message={`An email is on its way to you with new verification link. Please don't forget to check spam.`}
>
<div className="below-box">
<p>
Click{' '}
<Link to="/user-verify/resend">here</Link>{' '}
to resend verification link to your email.
</p>
</div>
</MessageBox>
</div>
) : (
<LoginForm onSubmit={this.submitHandler} {...this.props} />
)}
{/* LOGIN BOX */}
{!this.props.login.success
&& this.props.login.error
&& this.props.login.error === 'Verify your email first.' ?
<div>
<MessageBox
title='Your email is not verified.'
//eslint-disable-next-line
message={`An email is on its way to you with new verification link. Please don't forget to check spam.`} >
<div className="below-box">
<p>
Click <Link to="/user-verify/resend">here</Link> to resend verification link to your email.
</p>
</div>
</MessageBox>
</div> :
<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>
{/* 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>
);
}
{/* 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
};
return {
login: state.login,
};
};
const mapDispatchToProps = dispatch => bindActionCreators(
{ loginUser, loginError }, dispatch);
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,
]),
location: PropTypes.object,
}
loginUser: PropTypes.func.isRequired,
login: PropTypes.object,
success: PropTypes.bool,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
location: PropTypes.object,
};
LoginPage.displayName = 'LoginPage'
LoginPage.displayName = 'LoginPage';
export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);

View File

@@ -1,95 +1,107 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import RegisterForm from '../components/auth/RegisterForm';
import queryString from 'query-string';
import {PricingPlan} from '../config';
import { PricingPlan } from '../config';
import MessageBox from '../components/MessageBox';
import { savePlanId } from '../actions/register';
class RegisterPage extends React.Component {
componentWillUnmount() {
document.body.id = '';
document.body.className = '';
}
componentWillUnmount() {
document.body.id = '';
document.body.className = '';
}
componentDidMount() {
document.body.id = 'login';
document.body.className = 'register-page';
document.body.style.overflow = 'auto';
this.planId =
queryString.parse(this.props.location.search).planId || null;
componentDidMount() {
document.body.id = 'login';
document.body.className = 'register-page';
document.body.style.overflow = 'auto';
this.planId = queryString.parse(this.props.location.search).planId || null;
if (!this.planId) {
this.planId = PricingPlan.getPlans()[0].planId;
}
this.props.savePlanId(this.planId);
}
if(!this.planId){
this.planId = PricingPlan.getPlans()[0].planId;
}
this.props.savePlanId(this.planId);
}
render() {
return (
<div id="wrap" style={{ paddingTop: 0 }}>
{/* Header */}
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
render() {
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>
);
}
{/* 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'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
};
return {
register: state.register,
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
savePlanId
}, dispatch);
}
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
savePlanId,
},
dispatch
);
};
RegisterPage.propTypes = {
location: PropTypes.object.isRequired,
register:PropTypes.object,
success:PropTypes.bool,
savePlanId: PropTypes.func.isRequired
}
location: PropTypes.object.isRequired,
register: PropTypes.object,
success: PropTypes.bool,
savePlanId: PropTypes.func.isRequired,
};
RegisterPage.displayName = 'RegisterPage';

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { Validate } from '../config';
@@ -12,152 +12,198 @@ import queryString from 'query-string';
import { removeQuery } from '../store';
const errorStyle = {
color: '#c23d4b'
}
color: '#c23d4b',
};
export class ResendTokenForm extends Component {
state = {
serverResponse: ''
}
submitForm = (values) => {
this.props.resendToken(values);
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
const 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;
const resendTokenError = this.props.resendTokenState.error;
let header;
if(success) {
header = <span>Verification Email Sent</span>
} else if (resendTokenError) {
header = <span style={errorStyle} id="error-msg">{resendTokenError}</span>
} else if (serverResponse) {
header = <span style={errorStyle} id="error-msg">{serverResponse}</span>
} else {
header = <span>Resend verification email.</span>
}
state = {
serverResponse: '',
};
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" >
<div className="title">
<h2>
{header}
</h2>
submitForm = values => {
this.props.resendToken(values);
};
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
const 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;
const resendTokenError = this.props.resendTokenState.error;
let header;
if (success) {
header = <span>Verification Email Sent</span>;
} else if (resendTokenError) {
header = (
<span style={errorStyle} id="error-msg">
{resendTokenError}
</span>
);
} else if (serverResponse) {
header = (
<span style={errorStyle} id="error-msg">
{serverResponse}
</span>
);
} else {
header = <span>Resend verification email.</span>;
}
return (
<div id="wrap" style={{ paddingTop: 0 }}>
<div id="header">
<h1>
<a href="/">Fyipe</a>
</h1>
</div>
{this.props.resendTokenState.success && <p id="resend-verification-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>}
<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">
<div className="title">
<h2>{header}</h2>
</div>
{this.props.resendTokenState.success && (
<p
id="resend-verification-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 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>
)
}
{!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 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'
ResendTokenForm.displayName = 'ResendTokenForm';
function validate(values) {
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.'
}
else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.'
}
return errors;
const errors = {};
if (!Validate.text(values.email)) {
errors.email = 'Email is required.';
} else if (!Validate.email(values.email)) {
errors.email = 'Email is invalid.';
}
return errors;
}
const resendTokenForm = reduxForm({
form: 'resendTokenForm',
validate
form: 'resendTokenForm',
validate,
})(ResendTokenForm);
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
resendToken
}, dispatch);
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
resendToken,
},
dispatch
);
};
function mapStateToProps(state) {
return {
resendTokenState: state.resendToken
};
return {
resendTokenState: state.resendToken,
};
}
ResendTokenForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
resendTokenState: PropTypes.object.isRequired,
resendToken: PropTypes.func.isRequired,
location: PropTypes.object.isRequired
}
handleSubmit: PropTypes.func.isRequired,
resendTokenState: PropTypes.object.isRequired,
resendToken: PropTypes.func.isRequired,
location: PropTypes.object.isRequired,
};
export default connect(mapStateToProps, mapDispatchToProps)(resendTokenForm);
export default connect(mapStateToProps, mapDispatchToProps)(resendTokenForm);

View File

@@ -4,54 +4,54 @@ 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';
}
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>
);
}
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'
ResetPasswordPage.displayName = 'ResetPasswordPage';
export default connect(null, null)(ResetPasswordPage);
export default connect(null, null)(ResetPasswordPage);

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { ButtonSpinner } from '../components/basic/Loader';
@@ -10,124 +10,161 @@ import { Link } from 'react-router-dom';
import { identify, setUserId, logEvent } from '../analytics';
import { IS_DEV } from '../config';
const errorStyle = {color: '#c23d4b'};
const errorStyle = { color: '#c23d4b' };
export class VerifyAuthToken extends Component {
constructor(props) {
super(props);
this.props = props;
}
constructor(props) {
super(props);
this.props = props;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
submitForm = (values) => {
this.props.verifyAuthToken(values).then((user) => {
if (user && user.data && user.data.id) {
if (!IS_DEV) {
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id })
}
}
})
}
render() {
const { error } = this.props.login.authToken;
let header;
if (error) {
header = <span style={errorStyle}>{error}</span>;
} else {
header = <span>Two Factor Auth token.</span>;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
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" >
<div className="title"><h2>{header}</h2></div>
submitForm = values => {
this.props.verifyAuthToken(values).then(user => {
if (user && user.data && user.data.id) {
if (!IS_DEV) {
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id });
}
}
});
};
<p className="error-message hidden" />
<p className="message">Enter your auth token below to login.</p>
<div>
<p className="text">
<span>
<label htmlFor="token">Verification Token</label>
<Field
component={RenderField}
type="text"
name="token"
id="token"
placeholder="Token"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" disabled={this.props.login.authToken.requesting}>
{!this.props.login.authToken.requesting && <span>Verify token</span>}
{this.props.login.authToken.requesting && <ButtonSpinner />}
</button>
</p>
</div>
</div>
</form>
</div>
</div>
<div className="below-box">
<p>
Don&#39;t have your app authenticator? <Link to="/user-auth/backup">Use Backup code</Link>.
</p>
</div>
<div id="footer_spacer"/>
<div id="bottom">
<ul>
<li><Link to="/login">Sign In</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>
)
}
render() {
const { error } = this.props.login.authToken;
let header;
if (error) {
header = <span style={errorStyle}>{error}</span>;
} else {
header = <span>Two Factor Auth token.</span>;
}
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">
<div className="title">
<h2>{header}</h2>
</div>
<p className="error-message hidden" />
<p className="message">
Enter your auth token below to login.
</p>
<div>
<p className="text">
<span>
<label htmlFor="token">
Verification Token
</label>
<Field
component={RenderField}
type="text"
name="token"
id="token"
placeholder="Token"
/>
</span>
</p>
<p className="submit">
<button
type="submit"
className="button blue medium"
disabled={
this.props.login.authToken
.requesting
}
>
{!this.props.login.authToken
.requesting && (
<span>Verify token</span>
)}
{this.props.login.authToken
.requesting && (
<ButtonSpinner />
)}
</button>
</p>
</div>
</div>
</form>
</div>
</div>
<div className="below-box">
<p>
Don&#39;t have your app authenticator?{' '}
<Link to="/user-auth/backup">Use Backup code</Link>.
</p>
</div>
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/login">Sign In</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>
);
}
}
VerifyAuthToken.displayName = 'VerifyAuthToken';
function validate(values) {
const errors = {};
if (!values.token) {
errors.token = 'Please provide token.';
}
return errors;
const errors = {};
if (!values.token) {
errors.token = 'Please provide token.';
}
return errors;
}
const verifyAuthTokenForm = reduxForm({
form: 'verifyAuthToken',
validate
form: 'verifyAuthToken',
validate,
})(VerifyAuthToken);
const mapStateToProps = state => {
return {login: state.login};
return { login: state.login };
};
const mapDispatchToProps = dispatch => bindActionCreators(
{ verifyAuthToken }, dispatch
);
const mapDispatchToProps = dispatch =>
bindActionCreators({ verifyAuthToken }, dispatch);
VerifyAuthToken.propTypes = {
handleSubmit: PropTypes.func.isRequired,
verifyAuthToken: PropTypes.func.isRequired,
login: PropTypes.object,
}
handleSubmit: PropTypes.func.isRequired,
verifyAuthToken: PropTypes.func.isRequired,
login: PropTypes.object,
};
export default connect(mapStateToProps, mapDispatchToProps)(verifyAuthTokenForm);
export default connect(
mapStateToProps,
mapDispatchToProps
)(verifyAuthTokenForm);

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { ButtonSpinner } from '../components/basic/Loader';
@@ -10,119 +10,150 @@ import { Link } from 'react-router-dom';
import { identify, setUserId, logEvent } from '../analytics';
import { IS_DEV } from '../config';
const errorStyle = {color: '#c23d4b'};
const errorStyle = { color: '#c23d4b' };
export class VerifyBackupCode extends Component {
constructor(props) {
super(props);
this.props = props;
}
constructor(props) {
super(props);
this.props = props;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
submitForm = (values) => {
this.props.verifyBackupCode(values).then((user) => {
if (user && user.data && user.data.id) {
if (!IS_DEV) {
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id })
}
}
})
}
render() {
const { backupCode } = this.props.login;
let header;
if (backupCode.error) {
header = <span style={errorStyle}>{backupCode.error}</span>;
} else {
header = <span>Backup Code.</span>;
}
componentDidMount() {
document.body.id = 'login';
document.body.style.overflow = 'auto';
}
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" >
<div className="title"><h2>{header}</h2></div>
submitForm = values => {
this.props.verifyBackupCode(values).then(user => {
if (user && user.data && user.data.id) {
if (!IS_DEV) {
identify(user.data.id);
setUserId(user.data.id);
logEvent('Log in user', { id: user.data.id });
}
}
});
};
<p className="error-message hidden" />
<p className="message">Enter your backup code below to login.</p>
<div>
<p className="text">
<span>
<label htmlFor="code">Backup Code</label>
<Field
component={RenderField}
type="text"
name="code"
id="code"
placeholder="Backup Code"
/>
</span>
</p>
<p className="submit">
<button type="submit" className="button blue medium" disabled={backupCode.requesting}>
{!backupCode.requesting && <span>Verify Code</span>}
{backupCode.requesting && <ButtonSpinner />}
</button>
</p>
</div>
</div>
</form>
</div>
</div>
<div id="footer_spacer"/>
<div id="bottom">
<ul>
<li><Link to="/login">Sign In</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>
)
}
render() {
const { backupCode } = this.props.login;
let header;
if (backupCode.error) {
header = <span style={errorStyle}>{backupCode.error}</span>;
} else {
header = <span>Backup Code.</span>;
}
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">
<div className="title">
<h2>{header}</h2>
</div>
<p className="error-message hidden" />
<p className="message">
Enter your backup code below to login.
</p>
<div>
<p className="text">
<span>
<label htmlFor="code">
Backup Code
</label>
<Field
component={RenderField}
type="text"
name="code"
id="code"
placeholder="Backup Code"
/>
</span>
</p>
<p className="submit">
<button
type="submit"
className="button blue medium"
disabled={backupCode.requesting}
>
{!backupCode.requesting && (
<span>Verify Code</span>
)}
{backupCode.requesting && (
<ButtonSpinner />
)}
</button>
</p>
</div>
</div>
</form>
</div>
</div>
<div id="footer_spacer" />
<div id="bottom">
<ul>
<li>
<Link to="/login">Sign In</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>
);
}
}
VerifyBackupCode.displayName = 'VerifyBackupCode';
function validate(values) {
const errors = {};
if (!values.code) {
errors.code = 'Please provide a backup code.';
}
return errors;
const errors = {};
if (!values.code) {
errors.code = 'Please provide a backup code.';
}
return errors;
}
const verifyBackupCodeForm = reduxForm({
form: 'verifyBackupCode',
validate
form: 'verifyBackupCode',
validate,
})(VerifyBackupCode);
const mapStateToProps = state => {
return {login: state.login};
return { login: state.login };
};
const mapDispatchToProps = dispatch => bindActionCreators(
{ verifyBackupCode }, dispatch
);
const mapDispatchToProps = dispatch =>
bindActionCreators({ verifyBackupCode }, dispatch);
VerifyBackupCode.propTypes = {
handleSubmit: PropTypes.func.isRequired,
verifyBackupCode: PropTypes.func,
login: PropTypes.object,
}
handleSubmit: PropTypes.func.isRequired,
verifyBackupCode: PropTypes.func,
login: PropTypes.object,
};
export default connect(mapStateToProps, mapDispatchToProps)(verifyBackupCodeForm);
export default connect(
mapStateToProps,
mapDispatchToProps
)(verifyBackupCodeForm);

View File

@@ -6,7 +6,6 @@ import ResendToken from './ResendToken';
import VerifyAuthToken from './VerifyAuthToken';
import VerifyBackupCode from './VerifyBackupCode';
export default {
ResetPassword,
Register,
@@ -15,4 +14,4 @@ export default {
ResendToken,
VerifyAuthToken,
VerifyBackupCode,
}
};

View File

@@ -1,44 +1,41 @@
import * as types from '../constants/changePassword'
import * as types from '../constants/changePassword';
// The auth reducer. The starting state sets authentication
// based on a token being in local storage. In a real app,
// we would also want a util to check if the token is expired.
const initialState = {
requesting: false,
error: null,
success: false
requesting: false,
error: null,
success: false,
};
export default function register(state = initialState, action) {
switch (action.type) {
switch (action.type) {
case types.CHANGEPASSWORD_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null,
});
case types.CHANGEPASSWORD_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null
});
case types.CHANGEPASSWORD_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case types.CHANGEPASSWORD_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case types.CHANGEPASSWORD_FAILED:
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
case types.CHANGEPASSWORD_FAILED:
case types.RESET_CHANGEPASSWORD:
return Object.assign({}, state, initialState);
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
case types.RESET_CHANGEPASSWORD:
return Object.assign({}, state, initialState);
default:
return state;
}
}
default:
return state;
}
}

View File

@@ -16,12 +16,12 @@ const appReducer = combineReducers({
modal,
resetPassword,
changePassword,
resendToken
resendToken,
});
export default (state, action) => {
if(action.type === 'CLEAR_STORE'){
if (action.type === 'CLEAR_STORE') {
state = undefined;
}
return appReducer(state, action);
}
};

View File

@@ -1,147 +1,143 @@
import {
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILED,
RESET_LOGIN,
SAVE_STATUS_PAGE,
AUTH_VERIFICATION_FAILED,
AUTH_VERIFICATION_REQUEST,
AUTH_VERIFICATION_SUCCESS,
RESET_AUTH_VERIFICATION,
BACKUP_CODE_VERIFICATION_FAILED,
BACKUP_CODE_VERIFICATION_REQUEST,
BACKUP_CODE_VERIFICATION_SUCCESS,
RESET_BACKUP_CODE_VERIFICATION
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILED,
RESET_LOGIN,
SAVE_STATUS_PAGE,
AUTH_VERIFICATION_FAILED,
AUTH_VERIFICATION_REQUEST,
AUTH_VERIFICATION_SUCCESS,
RESET_AUTH_VERIFICATION,
BACKUP_CODE_VERIFICATION_FAILED,
BACKUP_CODE_VERIFICATION_REQUEST,
BACKUP_CODE_VERIFICATION_SUCCESS,
RESET_BACKUP_CODE_VERIFICATION,
} from '../constants/login';
// The auth reducer. The starting state sets authentication
// based on a token being in local storage. In a real app,
// we would also want a util to check if the token is expired.
const initialState = {
requesting: false,
user: {},
error: null,
success: false,
statusPageLogin: false,
statusPageURL: null,
authToken: {
requesting: false,
error: null,
success: false,
},
backupCode: {
requesting: false,
error: null,
success: false,
}
requesting: false,
user: {},
error: null,
success: false,
statusPageLogin: false,
statusPageURL: null,
authToken: {
requesting: false,
error: null,
success: false,
},
backupCode: {
requesting: false,
error: null,
success: false,
},
};
export default function register(state = initialState, action) {
switch (action.type) {
switch (action.type) {
case LOGIN_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null,
});
case LOGIN_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
user: action.payload,
});
case LOGIN_FAILED:
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
case LOGIN_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null
});
case LOGIN_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
user: action.payload,
});
case LOGIN_FAILED:
case RESET_LOGIN:
return Object.assign({}, state, initialState);
return Object.assign({}, state, {
requesting: false,
success:false,
error: action.payload,
});
case AUTH_VERIFICATION_REQUEST:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: true,
error: null,
success: true,
},
});
case AUTH_VERIFICATION_SUCCESS:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: false,
error: null,
success: true,
},
});
case AUTH_VERIFICATION_FAILED:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: false,
error: action.payload,
success: false,
},
});
case RESET_LOGIN:
return Object.assign({}, state, initialState);
case AUTH_VERIFICATION_REQUEST:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: true,
error: null,
success: true,
}
});
case AUTH_VERIFICATION_SUCCESS:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: false,
error: null,
success: true,
}
});
case AUTH_VERIFICATION_FAILED:
return Object.assign({}, state, {
...initialState,
authToken: {
...initialState.authToken,
requesting: false,
error: action.payload,
success: false,
}
});
case RESET_AUTH_VERIFICATION:
return Object.assign({}, state, initialState);
case RESET_AUTH_VERIFICATION:
return Object.assign({}, state, initialState);
// Use back up code to login a user
// Use back up code to login a user
case BACKUP_CODE_VERIFICATION_REQUEST:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: true,
error: null,
success: true,
}
});
case BACKUP_CODE_VERIFICATION_SUCCESS:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: false,
error: null,
success: true,
}
});
case BACKUP_CODE_VERIFICATION_FAILED:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: false,
error: action.payload,
success: false,
}
});
case BACKUP_CODE_VERIFICATION_REQUEST:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: true,
error: null,
success: true,
},
});
case BACKUP_CODE_VERIFICATION_SUCCESS:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: false,
error: null,
success: true,
},
});
case BACKUP_CODE_VERIFICATION_FAILED:
return Object.assign({}, state, {
...initialState,
backupCode: {
...initialState.backupCode,
requesting: false,
error: action.payload,
success: false,
},
});
case RESET_BACKUP_CODE_VERIFICATION:
return Object.assign({}, state, initialState);
case RESET_BACKUP_CODE_VERIFICATION:
return Object.assign({}, state, initialState);
case SAVE_STATUS_PAGE:
return Object.assign({}, state, {
statusPageLogin: action.payload.statusPageLogin,
statusPageURL: action.payload.statusPageURL
})
case SAVE_STATUS_PAGE:
return Object.assign({}, state, {
statusPageLogin: action.payload.statusPageLogin,
statusPageURL: action.payload.statusPageURL,
});
default:
return state;
}
default:
return state;
}
}

View File

@@ -1,24 +1,25 @@
import { OPEN_MODAL, CLOSE_MODAL} from '../constants/modal'
import { OPEN_MODAL, CLOSE_MODAL } from '../constants/modal';
const initialState = {
modals: [],
feedbackModalVisble:false
feedbackModalVisble: false,
};
export default (state = initialState, action) => {
switch (action.type) {
case OPEN_MODAL:
return Object.assign({}, state, {
modals: state.modals.concat(action.payload)
modals: state.modals.concat(action.payload),
});
case CLOSE_MODAL:
return Object.assign({}, state, {
modals: state.modals.filter(item => item.id !== action.payload.id)
modals: state.modals.filter(
item => item.id !== action.payload.id
),
});
default: return state;
default:
return state;
}
}
};

View File

@@ -1,164 +1,159 @@
import {
SIGNUP_SUCCESS,
SIGNUP_FAILED,
SIGNUP_STEP_INC,
SIGNUP_STEP_DEC,
SIGNUP_REQUEST,
RESET_SIGNUP,
SAVE_CARD_STATE,
SAVE_USER_STATE,
SAVE_COMPANY_STATE,
IS_USER_INVITED_FAILED,
IS_USER_INVITED_REQUEST,
IS_USER_INVITED_RESET,
IS_USER_INVITED_SUCCESS,
SKIP_CARD_STEP,
ADD_CARD_REQUEST,
ADD_CARD_SUCCESS,
ADD_CARD_FAILED,
SAVE_PLAN_ID
} from '../constants/register.js'
SIGNUP_SUCCESS,
SIGNUP_FAILED,
SIGNUP_STEP_INC,
SIGNUP_STEP_DEC,
SIGNUP_REQUEST,
RESET_SIGNUP,
SAVE_CARD_STATE,
SAVE_USER_STATE,
SAVE_COMPANY_STATE,
IS_USER_INVITED_FAILED,
IS_USER_INVITED_REQUEST,
IS_USER_INVITED_RESET,
IS_USER_INVITED_SUCCESS,
SKIP_CARD_STEP,
ADD_CARD_REQUEST,
ADD_CARD_SUCCESS,
ADD_CARD_FAILED,
SAVE_PLAN_ID,
} from '../constants/register.js';
// The register state reducer.
const initialState = {
addCard: {
addCard: {
requesting: false,
error: null,
success: false,
card: {}
card: {},
},
requesting: false,
step: 1,
user: {},
card: {},
company: {},
error: null,
success: false,
planId: null,
isUserInvited: {
requesting: false,
isUserInvited: null,
error: null,
success: false,
},
requesting: false,
step: 1,
user: {},
card: {},
company: {},
error: null,
success: false,
planId: null,
isUserInvited: {
requesting: false,
isUserInvited: null,
error: null,
success: false
}
};
export default function register(state = initialState, action) {
let incCount,decCount,stage;
switch (action.type) {
case SIGNUP_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null
});
case SIGNUP_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case SIGNUP_FAILED:
let incCount, decCount, stage;
switch (action.type) {
case SIGNUP_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null,
});
case SIGNUP_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case SIGNUP_FAILED:
return Object.assign({}, state, {
requesting: false,
isAuthenticated: false,
error: action.payload,
isUserInvited: {
...state.isUserInvited,
requesting: false,
},
});
return Object.assign({}, state, {
requesting: false,
isAuthenticated: false,
error: action.payload,
isUserInvited : {
...state.isUserInvited,
requesting: false,
}
});
case SIGNUP_STEP_INC:
incCount = state.step + 1;
case SIGNUP_STEP_INC:
incCount = state.step + 1;
return Object.assign({}, state, {
step: incCount,
error: null,
});
return Object.assign({}, state, {
step: incCount,
error: null
});
case SKIP_CARD_STEP:
stage = 3;
case SKIP_CARD_STEP:
stage = 3;
return Object.assign({}, state, {
step: stage,
error: null,
});
return Object.assign({}, state, {
step: stage,
error: null
});
case SIGNUP_STEP_DEC:
decCount = state.step - 1;
case SIGNUP_STEP_DEC:
decCount = state.step - 1;
return Object.assign({}, state, {
step: decCount,
error: null,
});
case SAVE_USER_STATE:
return Object.assign({}, state, {
user: action.payload,
});
case SAVE_CARD_STATE:
return Object.assign({}, state, {
card: action.payload,
});
case SAVE_COMPANY_STATE:
return Object.assign({}, state, {
company: action.payload,
});
return Object.assign({}, state, {
step: decCount,
error: null
});
case SAVE_USER_STATE:
case RESET_SIGNUP:
return Object.assign({}, state, initialState);
return Object.assign({}, state, {
user: action.payload
});
case SAVE_CARD_STATE:
case IS_USER_INVITED_FAILED:
return Object.assign({}, state, {
isUserInvited: {
requesting: false,
isUserInvited: null,
error: action.payload,
success: false,
},
});
case IS_USER_INVITED_REQUEST:
return Object.assign({}, state, {
isUserInvited: {
requesting: true,
isUserInvited: null,
error: null,
success: false,
},
});
return Object.assign({}, state, {
card: action.payload
});
case SAVE_COMPANY_STATE:
case IS_USER_INVITED_SUCCESS:
return Object.assign({}, state, {
...state,
isUserInvited: {
requesting: false,
isUserInvited: action.payload,
error: null,
success: false,
},
});
return Object.assign({}, state, {
company: action.payload
});
case RESET_SIGNUP:
return Object.assign({}, state, initialState);
case IS_USER_INVITED_FAILED:
return Object.assign({}, state, {
isUserInvited: {
requesting: false,
isUserInvited: null,
error: action.payload,
success: false
}
});
case IS_USER_INVITED_REQUEST:
return Object.assign({}, state, {
isUserInvited: {
requesting: true,
isUserInvited: null,
error: null,
success: false
}
});
case IS_USER_INVITED_SUCCESS:
return Object.assign({}, state, {
...state, isUserInvited: {
requesting: false,
isUserInvited: action.payload,
error: null,
success: false
}
});
case IS_USER_INVITED_RESET:
return Object.assign({}, state, {
...state, isUserInvited: {
requesting: false,
isUserInvited: null,
error: null,
success: false
}
});
case ADD_CARD_REQUEST:
case IS_USER_INVITED_RESET:
return Object.assign({}, state, {
...state,
isUserInvited: {
requesting: false,
isUserInvited: null,
error: null,
success: false,
},
});
case ADD_CARD_REQUEST:
return Object.assign({}, state, {
...state,
addCard: {
...state.addCard,
requesting: true
}
requesting: true,
},
});
case ADD_CARD_SUCCESS:
@@ -168,8 +163,8 @@ export default function register(state = initialState, action) {
requesting: false,
error: null,
success: true,
card: action.payload
}
card: action.payload,
},
});
case ADD_CARD_FAILED:
@@ -178,16 +173,15 @@ export default function register(state = initialState, action) {
addCard: {
requesting: false,
success: false,
error: action.payload
}
});
case SAVE_PLAN_ID:
error: action.payload,
},
});
case SAVE_PLAN_ID:
return Object.assign({}, state, {
planId: action.payload,
});
return Object.assign({}, state, {
planId: action.payload
});
default:
return state;
}
default:
return state;
}
}

View File

@@ -1,33 +1,35 @@
import {RESENDTOKEN_FAILED, RESENDTOKEN_REQUEST, RESENDTOKEN_SUCCESS} from '../constants/resendToken';
import {
RESENDTOKEN_FAILED,
RESENDTOKEN_REQUEST,
RESENDTOKEN_SUCCESS,
} from '../constants/resendToken';
const initialState = {
requesting: false,
error: null,
success: false
requesting: false,
error: null,
success: false,
};
export default function register(state = initialState, action) {
switch (action.type) {
case RESENDTOKEN_REQUEST:
return Object.assign({}, state, {
...state,
requesting: true
});
case RESENDTOKEN_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case RESENDTOKEN_FAILED:
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
default:
return state;
}
switch (action.type) {
case RESENDTOKEN_REQUEST:
return Object.assign({}, state, {
...state,
requesting: true,
});
case RESENDTOKEN_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case RESENDTOKEN_FAILED:
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
default:
return state;
}
}

View File

@@ -1,43 +1,44 @@
import {PASSWORDRESET_REQUEST,PASSWORDRESET_SUCCESS, PASSWORDRESET_FAILED, RESET_PASSWORDRESET } from '../constants/resetPassword';
import {
PASSWORDRESET_REQUEST,
PASSWORDRESET_SUCCESS,
PASSWORDRESET_FAILED,
RESET_PASSWORDRESET,
} from '../constants/resetPassword';
// The auth reducer. The starting state sets authentication
// based on a token being in local storage. In a real app,
// we would also want a util to check if the token is expired.
const initialState = {
requesting: false,
error: null,
success: false
requesting: false,
error: null,
success: false,
};
export default function register(state = initialState, action) {
switch (action.type) {
switch (action.type) {
case PASSWORDRESET_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null,
});
case PASSWORDRESET_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case PASSWORDRESET_FAILED:
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
case PASSWORDRESET_REQUEST:
return Object.assign({}, state, {
requesting: true,
error: null
});
case PASSWORDRESET_SUCCESS:
return Object.assign({}, state, {
requesting: false,
success: true,
error: null,
});
case PASSWORDRESET_FAILED:
case RESET_PASSWORDRESET:
return Object.assign({}, state, initialState);
return Object.assign({}, state, {
requesting: false,
success: false,
error: action.payload,
});
case RESET_PASSWORDRESET:
return Object.assign({}, state, initialState);
default:
return state;
}
default:
return state;
}
}

View File

@@ -1,109 +1,109 @@
import pages from './pages';
const {
Register,
Login,
ResetPassword,
ChangePassword,
ResendToken,
VerifyAuthToken,
VerifyBackupCode
Register,
Login,
ResetPassword,
ChangePassword,
ResendToken,
VerifyAuthToken,
VerifyBackupCode,
} = pages;
export const groups = [
{
group: 'public',
isPublic: true,
routes: [
{
title: 'Login',
path: '/login',
icon: 'home',
component: Login,
subRoutes: [],
isPublic: true,
visible: true,
index: 1
},
{
title: 'Register',
path: '/register',
icon: 'home',
component: Register,
subRoutes: [],
isPublic: true,
visible: true,
index: 2
},
{
title: 'Password Reset',
path: '/forgot-password',
icon: 'home',
component: ResetPassword,
subRoutes: [],
isPublic: true,
visible: true,
index: 3
},
{
title: 'Change Password',
path: '/change-password/:token',
icon: 'home',
component: ChangePassword,
subRoutes: [],
isPublic: true,
visible: true,
index: 4
},
{
title: 'Resend Verification',
path: '/user-verify/resend',
icon: 'home',
component: ResendToken,
subRoutes: [],
isPublic: true,
visible: true,
index: 5
},
{
title: 'Verify Authenticator Token',
path: '/user-auth/token',
icon: 'home',
component: VerifyAuthToken,
subRoutes: [],
isPublic: true,
visible: true,
index: 5
},
{
title: 'Verify Backup Code',
path: '/user-auth/backup',
icon: 'home',
component: VerifyBackupCode,
subRoutes: [],
isPublic: true,
visible: true,
index: 5
},
]
}
{
group: 'public',
isPublic: true,
routes: [
{
title: 'Login',
path: '/login',
icon: 'home',
component: Login,
subRoutes: [],
isPublic: true,
visible: true,
index: 1,
},
{
title: 'Register',
path: '/register',
icon: 'home',
component: Register,
subRoutes: [],
isPublic: true,
visible: true,
index: 2,
},
{
title: 'Password Reset',
path: '/forgot-password',
icon: 'home',
component: ResetPassword,
subRoutes: [],
isPublic: true,
visible: true,
index: 3,
},
{
title: 'Change Password',
path: '/change-password/:token',
icon: 'home',
component: ChangePassword,
subRoutes: [],
isPublic: true,
visible: true,
index: 4,
},
{
title: 'Resend Verification',
path: '/user-verify/resend',
icon: 'home',
component: ResendToken,
subRoutes: [],
isPublic: true,
visible: true,
index: 5,
},
{
title: 'Verify Authenticator Token',
path: '/user-auth/token',
icon: 'home',
component: VerifyAuthToken,
subRoutes: [],
isPublic: true,
visible: true,
index: 5,
},
{
title: 'Verify Backup Code',
path: '/user-auth/backup',
icon: 'home',
component: VerifyBackupCode,
subRoutes: [],
isPublic: true,
visible: true,
index: 5,
},
],
},
];
const joinFn = (acc = [], curr) => {
return acc.concat(curr);
return acc.concat(curr);
};
export const allRoutes = groups
.map(function merge(group) {
const { routes } = group;
const subRoutes = routes.map(route => route.subRoutes).reduce(joinFn);
return routes.concat(subRoutes);
})
.reduce(joinFn);
.map(function merge(group) {
const { routes } = group;
const subRoutes = routes.map(route => route.subRoutes).reduce(joinFn);
return routes.concat(subRoutes);
})
.reduce(joinFn);
export const getGroups = () => groups;
export default {
groups,
allRoutes
groups,
allRoutes,
};

View File

@@ -12,137 +12,136 @@
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if ('serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
if ('serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-workr.js`;
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-workr.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
window.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
return fetch(event.request);
}
)
);
});
}
});
window.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
})
);
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl, {scope: '.'})
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
navigator.serviceWorker
.register(swUrl, { scope: '.' })
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration: ', error);
});
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration: ', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null &&
contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

View File

@@ -8,18 +8,20 @@ import rootReducer from './reducers';
// A nice helper to tell us if we're on the server
export const isServer = !(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);
// export const history = createHistory();
const url = '/'
export const history = isServer ? createMemoryHistory({ initialEntries: [url]}) : createBrowserHistory();
const url = '/';
export const history = isServer
? createMemoryHistory({ initialEntries: [url] })
: createBrowserHistory();
export const removeQuery = () => {
const location = Object.assign({}, history.location);
delete location.search;
history.push(location);
const location = Object.assign({}, history.location);
delete location.search;
history.push(location);
};
const initialState = {};
const enhancers = [];
@@ -27,16 +29,15 @@ const logger = createLogger();
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
let devToolsExtension;
if (!isServer) {
devToolsExtension = window.devToolsExtension;
}
middleware.push(logger);
let devToolsExtension
if (!isServer) {
devToolsExtension = window.devToolsExtension;
}
middleware.push(logger);
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension());
}
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension());
}
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);

View File

@@ -3,17 +3,17 @@ const workboxBuild = require('workbox-build');
// NOTE: This should be run *AFTER* all your assets are built
const buildSW = () => {
// This will return a Promise
return workboxBuild.injectManifest({
swSrc: 'src/sw-template.js', // this is your sw template file
swDest: 'build/service-workr.js', // this will be created in the build step
globDirectory: 'build',
globPatterns: [
'**\/*.{js,css,html,png}',
]
}).then(({count, size}) => {
// Optionally, log any warnings and details.
return `${count} files will be precached, totaling ${size} bytes.`;
});
}
// This will return a Promise
return workboxBuild
.injectManifest({
swSrc: 'src/sw-template.js', // this is your sw template file
swDest: 'build/service-workr.js', // this will be created in the build step
globDirectory: 'build',
globPatterns: ['**/*.{js,css,html,png}'],
})
.then(({ count, size }) => {
// Optionally, log any warnings and details.
return `${count} files will be precached, totaling ${size} bytes.`;
});
};
buildSW();

View File

@@ -1,30 +1,29 @@
/* eslint-disable */
if ('function' === typeof importScripts) {
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/3.5.0/workbox-sw.js'
);
/* global workbox */
if (workbox) {
/* injection point for manifest files. */
workbox.precaching.precacheAndRoute([]);
/* custom cache rules*/
workbox.routing.registerNavigationRoute('/index.html', {
blacklist: [/^\/_/, /\/[^\/]+\.[^\/]+$/],
});
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg)$/,
workbox.strategies.cacheFirst({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
})
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/3.5.0/workbox-sw.js'
);
}
/* global workbox */
if (workbox) {
/* injection point for manifest files. */
workbox.precaching.precacheAndRoute([]);
/* custom cache rules*/
workbox.routing.registerNavigationRoute('/index.html', {
blacklist: [/^\/_/, /\/[^\/]+\.[^\/]+$/],
});
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg)$/,
workbox.strategies.cacheFirst({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
})
);
}
}

View File

@@ -1,79 +1,99 @@
const puppeteer = require('puppeteer');
var should = require('should');
var utils = require('./test-utils');
const should = require('should');
const utils = require('./test-utils');
let browser;
let page;
let email = utils.generateRandomBusinessEmail();
let password = utils.generateRandomString();
const email = utils.generateRandomBusinessEmail();
const password = utils.generateRandomString();
const user = {
email,
password
password,
};
describe('Change Password API', () => {
beforeAll(async () => {
jest.setTimeout(15000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
});
beforeAll(async () => {
afterAll(async () => {
await browser.close();
});
jest.setTimeout(15000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
});
it('Should not allow change of password if password and confirm password do not math', async () => {
await page.goto(
utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken',
{ waitUntil: 'networkidle2' }
);
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', user.password);
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', 'unmatchingPassword');
await page.click('button[type=submit]');
await page.waitForSelector(
'#confirmPasswordField > span > span:nth-child(2)'
);
const html = await page.$eval(
'#confirmPasswordField > span > span:nth-child(2)',
e => {
return e.innerHTML;
}
);
should.exist(html);
html.should.containEql('Password and confirm password should match.');
}, 160000);
afterAll(async () => {
await browser.close();
});
it('Should submit if password is less than 8 characters', async () => {
await page.goto(
utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken',
{ waitUntil: 'networkidle2' }
);
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', '123456');
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', '123456');
await page.click('button[type=submit]');
await page.waitForSelector('#passwordField > span > span:nth-child(1)');
const html = await page.$eval(
'#passwordField > span > span:nth-child(2)',
e => {
return e.innerHTML;
}
);
should.exist(html);
html.should.containEql('Password should be atleast 8 characters long');
}, 160000);
it('Should not allow change of password if password and confirm password do not math', async () => {
await page.goto(utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken', { waitUntil: 'networkidle2' });
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', user.password);
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', 'unmatchingPassword');
await page.click('button[type=submit]');
await page.waitForSelector('#confirmPasswordField > span > span:nth-child(2)');
const html = await page.$eval('#confirmPasswordField > span > span:nth-child(2)', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql("Password and confirm password should match.");
}, 160000);
it('Should submit if password is less than 8 characters', async () => {
await page.goto(utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken', { waitUntil: 'networkidle2' });
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', '123456');
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', '123456');
await page.click('button[type=submit]');
await page.waitForSelector('#passwordField > span > span:nth-child(1)');
const html = await page.$eval('#passwordField > span > span:nth-child(2)', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql("Password should be atleast 8 characters long");
}, 160000);
it('Should submit if password is missing', async () => {
await page.goto(utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken', { waitUntil: 'networkidle2' });
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', '');
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', '123456');
await page.click('button[type=submit]');
await page.waitForSelector('#passwordField > span > span:nth-child(1)');
const html = await page.$eval('#passwordField > span > span:nth-child(2)', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql("Password is required.");
}, 160000);
it('Should submit if password is missing', async () => {
await page.goto(
utils.ACCOUNTS_URL + '/change-password/thisisaWrongRestToken',
{ waitUntil: 'networkidle2' }
);
await page.waitForSelector('#password');
await page.click('input[name=password]');
await page.type('input[name=password]', '');
await page.waitForSelector('#confirmPassword');
await page.click('input[name=confirmPassword]');
await page.type('input[name=confirmPassword]', '123456');
await page.click('button[type=submit]');
await page.waitForSelector('#passwordField > span > span:nth-child(1)');
const html = await page.$eval(
'#passwordField > span > span:nth-child(2)',
e => {
return e.innerHTML;
}
);
should.exist(html);
html.should.containEql('Password is required.');
}, 160000);
});

View File

@@ -1,25 +1,25 @@
const puppeteer = require('puppeteer');
var should = require('should');
var utils = require('./test-utils');
var init = require('./test-init');
const utils = require('./test-utils');
const init = require('./test-init');
let browser;
let page;
let email = utils.generateRandomBusinessEmail();
let password = '1234567890';
const email = utils.generateRandomBusinessEmail();
const password = '1234567890';
const user = {
email,
password
password,
};
describe('Login API', () => {
beforeAll(async () => {
jest.setTimeout(20000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
});
afterAll(async () => {
@@ -27,7 +27,9 @@ describe('Login API', () => {
});
it('Users cannot login with incorrect credentials', async () => {
await page.goto(utils.ACCOUNTS_URL + '/login', { waitUntil: 'networkidle2' });
await page.goto(utils.ACCOUNTS_URL + '/login', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#login-button');
await page.click('input[name=email]');
await page.type('input[name=email]', user.email);
@@ -35,7 +37,7 @@ describe('Login API', () => {
await page.type('input[name=password]', user.password);
await page.click('button[type=submit]');
await page.waitFor(10000);
const html = await page.$eval('#main-body', (e) => {
const html = await page.$eval('#main-body', e => {
return e.innerHTML;
});
html.should.containEql('User does not exist.');
@@ -45,18 +47,18 @@ describe('Login API', () => {
await init.registerUser(user, page);
await init.loginUser(user, page);
var localStorageData = await page.evaluate(() => {
let json = {};
const localStorageData = await page.evaluate(() => {
const json = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
json[key] = localStorage.getItem(key);
}
return json;
});
await page.waitFor(10000);
localStorageData.should.have.property('access_token');
localStorageData.should.have.property('email', email);
page.url().should.containEql(utils.DASHBOARD_URL);
}, 160000);
});
});

View File

@@ -1,25 +1,25 @@
const puppeteer = require('puppeteer');
var should = require('should');
var utils = require('./test-utils');
var init = require('./test-init');
const utils = require('./test-utils');
const init = require('./test-init');
let browser;
let page, userCredentials;
let page;
let email = utils.generateRandomBusinessEmail();
let password = utils.generateRandomString();
const email = utils.generateRandomBusinessEmail();
const password = utils.generateRandomString();
const user = {
email,
password
password,
};
describe('Registration API', () => {
beforeAll(async () => {
jest.setTimeout(15000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
});
afterAll(async () => {
@@ -28,7 +28,9 @@ describe('Registration API', () => {
it('User cannot register with invalid email', async () => {
const invalidEmail = 'invalidEmail';
await page.goto(utils.ACCOUNTS_URL + '/register', { waitUntil: 'networkidle2' });
await page.goto(utils.ACCOUNTS_URL + '/register', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', invalidEmail);
@@ -45,15 +47,17 @@ describe('Registration API', () => {
await page.click('button[type=submit]');
await page.waitFor(1000);
const html = await page.$eval('#email', (e) => {
return e.innerHTML
const html = await page.$eval('#email', e => {
return e.innerHTML;
});
html.should.containEql('Email is not valid.')
html.should.containEql('Email is not valid.');
}, 160000);
it('User cannot register with personal email', async () => {
const personalEmail = 'personalEmail@gmail.com'
await page.goto(utils.ACCOUNTS_URL + '/register', { waitUntil: 'networkidle2' });
const personalEmail = 'personalEmail@gmail.com';
await page.goto(utils.ACCOUNTS_URL + '/register', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', personalEmail);
@@ -69,18 +73,18 @@ describe('Registration API', () => {
await page.type('input[name=confirmPassword]', user.password);
await page.click('button[type=submit]');
await page.waitFor(1000);
const html = await page.$eval('#email', (e) => {
return e.innerHTML
const html = await page.$eval('#email', e => {
return e.innerHTML;
});
html.should.containEql('Please enter a business email address.')
html.should.containEql('Please enter a business email address.');
}, 16000);
it('Should register User with valid details', async () => {
await init.registerUser(user, page);
await page.waitFor(15000);
const html = await page.$eval('#main-body', (e) => {
const html = await page.$eval('#main-body', e => {
return e.innerHTML;
});
html.should.containEql('Activate your Fyipe account');
}, 160000);
});
});

View File

@@ -1,55 +1,63 @@
/* eslint-disable quotes */
const puppeteer = require('puppeteer');
var should = require('should');
var utils = require('./test-utils');
var init = require('./test-init');
const should = require('should');
const utils = require('./test-utils');
const init = require('./test-init');
let browser;
let page, userCredentials;
let page;
let email = utils.generateRandomBusinessEmail();
let password = utils.generateRandomString();
const email = utils.generateRandomBusinessEmail();
const password = utils.generateRandomString();
const user = { email, password };
describe('Resend Verification API', () => {
beforeAll(async () => {
jest.setTimeout(30000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
});
beforeAll(async () => {
afterAll(async () => {
await browser.close();
});
jest.setTimeout(30000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
});
it('Should not resend verification token if a user associated with the email does not exist', async () => {
await page.goto(utils.ACCOUNTS_URL + '/user-verify/resend', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', 'invalid@email.com');
await page.click('button[type=submit]');
await page.waitForSelector('#error-msg');
const html = await page.$eval('#error-msg', e => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql('No user associated with this account');
}, 160000);
afterAll(async () => {
await browser.close();
});
it('Should not resend verification token if a user associated with the email does not exist', async () => {
await page.goto(utils.ACCOUNTS_URL + '/user-verify/resend', { waitUntil: 'networkidle2' });
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', 'invalid@email.com');
await page.click('button[type=submit]');
await page.waitForSelector('#error-msg');
const html = await page.$eval('#error-msg', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql("No user associated with this account");
}, 160000);
it('Should resend verification token successfully', async () => {
await init.registerUser(user, page);
await page.goto(utils.ACCOUNTS_URL + '/user-verify/resend', { waitUntil: 'networkidle2' });
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
await page.click('button[type=submit]');
await page.waitForSelector('#resend-verification-success');
const html = await page.$eval('#resend-verification-success', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql(" An email is on its way to you with new verification link. Please don't forget to check spam.");
}, 160000);
it('Should resend verification token successfully', async () => {
await init.registerUser(user, page);
await page.goto(utils.ACCOUNTS_URL + '/user-verify/resend', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
await page.click('button[type=submit]');
await page.waitForSelector('#resend-verification-success');
const html = await page.$eval('#resend-verification-success', e => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql(
" An email is on its way to you with new verification link. Please don't forget to check spam."
);
}, 160000);
});

View File

@@ -1,58 +1,66 @@
/* eslint-disable quotes */
const puppeteer = require('puppeteer');
var should = require('should');
var utils = require('./test-utils');
var init = require('./test-init');
const should = require('should');
const utils = require('./test-utils');
const init = require('./test-init');
let browser;
let page, userCredentials;
let page;
let email = utils.generateRandomBusinessEmail();
let password = utils.generateRandomString();
const email = utils.generateRandomBusinessEmail();
const password = utils.generateRandomString();
const user = {
email,
password
password,
};
describe('Reset Password API', () => {
beforeAll(async () => {
jest.setTimeout(15000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
);
});
beforeAll(async () => {
afterAll(async () => {
await browser.close();
});
jest.setTimeout(15000);
browser = await puppeteer.launch(utils.puppeteerLaunchConfig);
page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
});
it('Should reset password successfully', async () => {
await init.registerUser(user, page);
await page.goto(utils.ACCOUNTS_URL + '/forgot-password', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
await page.click('button[type=submit]');
await page.waitForSelector('#reset-password-success');
const html = await page.$eval('#reset-password-success', e => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql(
" An email is on its way to you. Follow the instructions to reset your password. Please don't forget to check spam. "
);
}, 160000);
afterAll(async () => {
await browser.close();
});
it('Should reset password successfully', async () => {
await init.registerUser(user, page)
await page.goto(utils.ACCOUNTS_URL + '/forgot-password', { waitUntil: 'networkidle2' });
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
await page.click('button[type=submit]');
await page.waitForSelector('#reset-password-success');
const html = await page.$eval('#reset-password-success', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql(" An email is on its way to you. Follow the instructions to reset your password. Please don't forget to check spam. ");
}, 160000);
it('User cannot reset password with non-existing email', async () => {
await page.goto(utils.ACCOUNTS_URL + '/forgot-password', { waitUntil: 'networkidle2' });
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', utils.generateWrongEmail());
await page.click('button[type=submit]');
await page.waitForSelector('#error-msg');
const html = await page.$eval('#error-msg', (e) => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql('User does not exist.');
}, 160000);
});
it('User cannot reset password with non-existing email', async () => {
await page.goto(utils.ACCOUNTS_URL + '/forgot-password', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', utils.generateWrongEmail());
await page.click('button[type=submit]');
await page.waitForSelector('#error-msg');
const html = await page.$eval('#error-msg', e => {
return e.innerHTML;
});
should.exist(html);
html.should.containEql('User does not exist.');
}, 160000);
});

View File

@@ -1,17 +1,26 @@
const utils = require('./test-utils');
const cards = ['4000056655665556', '4242424242424242', '5555555555554444', '2223003122003222', '5200828282828210', '5105105105105100']
module.exports = {
const cards = [
'4000056655665556',
'4242424242424242',
'5555555555554444',
'2223003122003222',
'5200828282828210',
'5105105105105100',
];
module.exports = {
/**
*
* @param { ObjectConstructor } user
* @param { string } page
*
* @param { ObjectConstructor } user
* @param { string } page
* @description Registers a new user.
* @returns { void }
*/
registerUser: async function (user, page){
registerUser: async function(user, page) {
const { email } = user;
let frame, elementHandle;
await page.goto(utils.ACCOUNTS_URL + '/register', { waitUntil: 'networkidle2' });
await page.goto(utils.ACCOUNTS_URL + '/register', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#email');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
@@ -36,22 +45,26 @@ module.exports = {
elementHandle = await page.$('iframe[name=__privateStripeFrame5]');
frame = await elementHandle.contentFrame();
await frame.waitForSelector('input[name=cardnumber]');
await frame.type('input[name=cardnumber]', cards[Math.floor(Math.random() * cards.length)], {
delay:50
});
await frame.type(
'input[name=cardnumber]',
cards[Math.floor(Math.random() * cards.length)],
{
delay: 50,
}
);
elementHandle = await page.$('iframe[name=__privateStripeFrame6]');
frame = await elementHandle.contentFrame();
await frame.waitForSelector('input[name=cvc]');
await frame.type('input[name=cvc]', '123', {
delay:50
delay: 50,
});
elementHandle = await page.$('iframe[name=__privateStripeFrame7]');
frame = await elementHandle.contentFrame();
await frame.waitForSelector('input[name=exp-date]');
await frame.type('input[name=exp-date]', '11/23', {
delay:50
delay: 50,
});
await page.click('input[name=address1]');
await page.type('input[name=address1]', utils.user.address.streetA);
@@ -63,17 +76,18 @@ module.exports = {
await page.type('input[name=state]', utils.user.address.state);
await page.click('input[name=zipCode]');
await page.type('input[name=zipCode]', utils.user.address.zipcode);
await page.select('#country', 'India')
await page.waitFor(60000); //wait for a second because of stripe rate limits.
await page.select('#country', 'India');
await page.waitFor(60000); //wait for a second because of stripe rate limits.
await page.click('button[type=submit]');
await page.waitForSelector('.request-reset-step', {
timeout: 60000
})
timeout: 60000,
});
},
loginUser: async function (user, page){
loginUser: async function(user, page) {
const { email, password } = user;
await page.goto(utils.ACCOUNTS_URL + '/login', { waitUntil: 'networkidle2' });
await page.goto(utils.ACCOUNTS_URL + '/login', {
waitUntil: 'networkidle2',
});
await page.waitForSelector('#login-button');
await page.click('input[name=email]');
await page.type('input[name=email]', email);
@@ -81,5 +95,5 @@ module.exports = {
await page.type('input[name=password]', password);
await page.click('button[type=submit]');
await page.waitFor(10000);
}
}
},
};

View File

@@ -5,36 +5,49 @@ const DASHBOARD_URL = 'http://localhost:3000';
const puppeteerLaunchConfig = {
args: [
'--proxy-server=',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920x1080',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-web-security'
'--proxy-server=',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920x1080',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-web-security',
],
};
};
const user = faker.helpers.createCard();
function generateWrongEmail() {
return Math.random().toString(36).substring(8) + '@' + Math.random().toString(24).substring(8) + '.com';
return (
Math.random()
.toString(36)
.substring(8) +
'@' +
Math.random()
.toString(24)
.substring(8) +
'.com'
);
}
function generateRandomString(){
return Math.random().toString(36).substring(10)
function generateRandomString() {
return Math.random()
.toString(36)
.substring(10);
}
function generateRandomBusinessEmail(){
return `${Math.random().toString(36).substring(7)}@${Math.random().toString(36).substring(5)}.com`;
function generateRandomBusinessEmail() {
return `${Math.random()
.toString(36)
.substring(7)}@${Math.random()
.toString(36)
.substring(5)}.com`;
}
module.exports = {
ACCOUNTS_URL,
DASHBOARD_URL,
@@ -42,5 +55,5 @@ module.exports = {
user,
generateWrongEmail,
generateRandomString,
generateRandomBusinessEmail
generateRandomBusinessEmail,
};

View File

@@ -1,2 +1 @@
# fyipe-admin-dashboard

View File

@@ -5,7 +5,7 @@ const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(3100);
app.listen(3100);

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +1,86 @@
{
"name": "fyipe-admin-dashboard",
"version": "3.0.1891",
"private": true,
"dependencies": {
"acorn": "^7.1.0",
"axios": "^0.18.0",
"browserslist": "^4.6.1",
"card-validator": "^6.2.0",
"clipboard": "^2.0.1",
"express": "^4.16.4",
"file-saver": "^2.0.1",
"font-awesome": "^4.7.0",
"fuzzy-match-utils": "^1.3.0",
"history": "^4.7.2",
"jest": "^24.7.1",
"js-uuid": "0.0.6",
"loadable-components": "^2.2.3",
"mixpanel-browser": "^2.22.3",
"moment": "^2.22.2",
"prop-types": "^15.6.1",
"react": "^16.5.2",
"react-click-outside": "github:tj/react-click-outside",
"react-dom": "^16.5.2",
"react-frontload": "^1.0.3",
"react-ga": "^2.5.3",
"react-json-view": "^1.19.1",
"react-mixpanel": "0.0.11",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
"react-scripts": "^3.4.0",
"react-select-fyipe": "^2.1.8",
"react-widgets": "^4.4.9",
"redux": "^3.7.2",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0",
"sane-email-validation": "^1.1.0",
"universal-cookie": "^4.0.0",
"valid-url": "^1.0.9"
},
"scripts": {
"lint": "eslint .",
"fix-lint": "eslint . --fix",
"dev": "PORT=3100 react-scripts start",
"build": "react-scripts build",
"test": "jest src/test/puppeteer/index.test.js",
"start": "node index.js",
"audit": "npm-audit-ci-wrapper --threshold=low",
"dep-check": "depcheck ./ --skip-missing=true --ignores='eslint,babel-*,browserslist,loadable-components,js-uuid,acorn'"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"depcheck": "^0.9.2",
"eslint": "^6.1.0",
"jest-localstorage-mock": "^2.2.0",
"npm-audit-ci-wrapper": "^2.4.3",
"redux-logger": "^3.0.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"
]
}
"name": "fyipe-admin-dashboard",
"version": "3.0.1891",
"private": true,
"dependencies": {
"acorn": "^7.1.0",
"axios": "^0.18.0",
"browserslist": "^4.6.1",
"card-validator": "^6.2.0",
"clipboard": "^2.0.1",
"express": "^4.16.4",
"file-saver": "^2.0.1",
"font-awesome": "^4.7.0",
"fuzzy-match-utils": "^1.3.0",
"history": "^4.7.2",
"jest": "^24.7.1",
"js-uuid": "0.0.6",
"loadable-components": "^2.2.3",
"mixpanel-browser": "^2.22.3",
"moment": "^2.22.2",
"prop-types": "^15.6.1",
"react": "^16.5.2",
"react-click-outside": "github:tj/react-click-outside",
"react-dom": "^16.5.2",
"react-frontload": "^1.0.3",
"react-ga": "^2.5.3",
"react-json-view": "^1.19.1",
"react-mixpanel": "0.0.11",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
"react-scripts": "^3.4.0",
"react-select-fyipe": "^2.1.8",
"react-widgets": "^4.4.9",
"redux": "^3.7.2",
"redux-form": "^7.3.0",
"redux-thunk": "^2.2.0",
"sane-email-validation": "^1.1.0",
"universal-cookie": "^4.0.0",
"valid-url": "^1.0.9"
},
"scripts": {
"lint": "eslint .",
"fix-lint": "eslint . --fix",
"dev": "PORT=3100 react-scripts start",
"build": "react-scripts build",
"test": "jest src/test/puppeteer/index.test.js",
"start": "node index.js",
"audit": "npm-audit-ci-wrapper --threshold=low",
"dep-check": "depcheck ./ --skip-missing=true --ignores='eslint,babel-*,browserslist,loadable-components,js-uuid,acorn'"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"depcheck": "^0.9.2",
"eslint": "^6.1.0",
"jest-localstorage-mock": "^2.2.0",
"npm-audit-ci-wrapper": "^2.4.3",
"redux-logger": "^3.0.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

@@ -11,57 +11,55 @@ import Cookies from 'universal-cookie';
import 'font-awesome/css/font-awesome.min.css';
if (!isServer) {
history.listen(location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
});
history.listen(location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
});
}
const cookies = new Cookies();
const userData = cookies.get('admin-data');
if (userData !== undefined){
User.setUserId(userData.id);
User.setAccessToken(userData.tokens.jwtAccessToken);
User.setEmail(userData.email);
User.setName(userData.name);
if (userData !== undefined) {
User.setUserId(userData.id);
User.setAccessToken(userData.tokens.jwtAccessToken);
User.setEmail(userData.email);
User.setName(userData.name);
}
cookies.remove('admin-data', {domain: DOMAIN_URL });
cookies.remove('admin-data', { domain: DOMAIN_URL });
if (!User.isLoggedIn()){
window.location = ACCOUNTS_URL;
if (!User.isLoggedIn()) {
window.location = ACCOUNTS_URL;
}
const App = () => (
<div style={{ height: '100%' }}>
<Router history={history}>
<Switch>
{allRoutes.filter(route => route.visible).map((route, index) => {
return (
<Route
exact
path={route.path}
key={index}
component={(route.component)}
/>
)
})}
<Route
path={'/:404_path'}
key={'404'}
component={NotFound}
/>
<Redirect to="/users" />
</Switch>
</Router>
<BackboneModals />
</div>
<div style={{ height: '100%' }}>
<Router history={history}>
<Switch>
{allRoutes
.filter(route => route.visible)
.map((route, index) => {
return (
<Route
exact
path={route.path}
key={index}
component={route.component}
/>
);
})}
<Route path={'/:404_path'} key={'404'} component={NotFound} />
<Redirect to="/users" />
</Switch>
</Router>
<BackboneModals />
</div>
);
App.displayName = 'App'
App.displayName = 'App';
function mapStateToProps(state) {
return state.login;
return state.login;
}
export default connect(mapStateToProps)(App);

View File

@@ -4,105 +4,103 @@ import errors from '../errors';
// Fetch All Audit Logs
export const fetchAuditLogsRequest = () => {
return {
type: types.FETCH_AUDITLOGS_REQUEST
};
return {
type: types.FETCH_AUDITLOGS_REQUEST,
};
};
export const fetchAuditLogsSuccess = auditLogs => {
return {
type: types.FETCH_AUDITLOGS_SUCCESS,
payload: auditLogs
};
return {
type: types.FETCH_AUDITLOGS_SUCCESS,
payload: auditLogs,
};
};
export const fetchAuditLogsError = error => {
return {
type: types.FETCH_AUDITLOGS_FAILURE,
payload: error
};
return {
type: types.FETCH_AUDITLOGS_FAILURE,
payload: error,
};
};
export const fetchAuditLogs = (skip, limit) => async dispatch => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
dispatch(fetchAuditLogsRequest());
dispatch(fetchAuditLogsRequest());
try {
const response = await getApi(
`audit-logs?skip=${skip}&limit=${limit}`
);
const data = response.data;
try {
const response = await getApi(`audit-logs?skip=${skip}&limit=${limit}`);
const data = response.data;
dispatch(fetchAuditLogsSuccess(data));
dispatch(fetchAuditLogsSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchAuditLogsError(errors(errorMsg)));
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchAuditLogsError(errors(errorMsg)));
}
};
// Search Audit Logs.
export const searchAuditLogsRequest = () => {
return {
type: types.SEARCH_AUDITLOGS_REQUEST
};
return {
type: types.SEARCH_AUDITLOGS_REQUEST,
};
};
export const searchAuditLogsSuccess = auditLogs => {
return {
type: types.SEARCH_AUDITLOGS_SUCCESS,
payload: auditLogs
};
return {
type: types.SEARCH_AUDITLOGS_SUCCESS,
payload: auditLogs,
};
};
export const searchAuditLogsError = error => {
return {
type: types.SEARCH_AUDITLOGS_FAILURE,
payload: error
};
return {
type: types.SEARCH_AUDITLOGS_FAILURE,
payload: error,
};
};
export const searchAuditLogs = (filter, skip, limit) => async dispatch => {
const values = {
filter
};
const values = {
filter,
};
dispatch(searchAuditLogsRequest());
dispatch(searchAuditLogsRequest());
try {
const response = await postApi(
`audit-logs/search?skip=${skip}&limit=${limit}`,
values
);
const data = response.data;
try {
const response = await postApi(
`audit-logs/search?skip=${skip}&limit=${limit}`,
values
);
const data = response.data;
dispatch(searchAuditLogsSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
dispatch(searchAuditLogsSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(searchAuditLogsError(errors(errorMsg)));
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(searchAuditLogsError(errors(errorMsg)));
}
};

View File

@@ -1,29 +1,29 @@
import * as types from '../constants/logout'
import * as types from '../constants/logout';
// Three possible states for our logout process as well.
// Since we are using JWTs, we just need to remove the token
// from localStorage. These actions are more useful if we
// were calling the API to log the user out
export const requestLogout = () => {
return {
type: types.LOGOUT_REQUEST,
isFetching: true,
isAuthenticated: true
}
}
return {
type: types.LOGOUT_REQUEST,
isFetching: true,
isAuthenticated: true,
};
};
export const receiveLogout = () => {
return {
type: types.LOGOUT_SUCCESS,
isFetching: false,
isAuthenticated: false
}
}
return {
type: types.LOGOUT_SUCCESS,
isFetching: false,
isAuthenticated: false,
};
};
// Logs the user out
export const logoutUser = () => dispatch => {
dispatch(requestLogout())
localStorage.removeItem('id_token')
localStorage.removeItem('access_token')
dispatch(receiveLogout())
}
dispatch(requestLogout());
localStorage.removeItem('id_token');
localStorage.removeItem('access_token');
dispatch(receiveLogout());
};

View File

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

View File

@@ -1,13 +1,13 @@
import * as types from '../constants/notification'
import * as types from '../constants/notification';
export const openNotificationMenu = () => {
return {
type: types.OPEN_NOTIFICATION_MENU
};
}
return {
type: types.OPEN_NOTIFICATION_MENU,
};
};
export const closeNotificationMenu = error => {
return {
type: types.CLOSE_NOTIFICATION_MENU,
payload : error
};
}
return {
type: types.CLOSE_NOTIFICATION_MENU,
payload: error,
};
};

View File

@@ -1,4 +1,4 @@
import {getApi, deleteApi, postApi} from '../api';
import { getApi, deleteApi, postApi } from '../api';
import * as types from '../constants/probe';
import errors from '../errors';
@@ -7,21 +7,21 @@ import errors from '../errors';
export function probeRequest(promise) {
return {
type: types.PROBE_REQUEST,
payload: promise
payload: promise,
};
}
export function probeError(error) {
return {
type: types.PROBE_FAILED,
payload: error
payload: error,
};
}
export function probeSuccess(probes) {
return {
type: types.PROBE_SUCCESS,
payload: probes
payload: probes,
};
}
@@ -36,142 +36,140 @@ export function getProbes(skip = 0, limit = 10) {
skip = parseInt(skip);
limit = parseInt(limit);
return function (dispatch) {
return function(dispatch) {
let promise = null;
promise = getApi(`probe/?skip=${skip}&limit=${limit}`);
promise = getApi(`probe/?skip=${skip}&limit=${limit}`);
dispatch(probeRequest(promise));
promise.then(function (probes) {
probes.data.skip = skip || 0;
probes.data.limit = limit || 10;
dispatch(probeSuccess(probes.data));
}, function (error) {
if (error && error.response && error.response.data)
error = error.response.data;
if (error && error.data) {
error = error.data;
promise.then(
function(probes) {
probes.data.skip = skip || 0;
probes.data.limit = limit || 10;
dispatch(probeSuccess(probes.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(probeError(errors(error)));
}
if (error && error.message) {
error = error.message;
}
else {
error = 'Network Error';
}
dispatch(probeError(errors(error)));
});
);
};
}
//Delete project
export const deleteProbeRequest = () => {
return {
type: types.DELETE_PROBE_REQUEST,
};
}
return {
type: types.DELETE_PROBE_REQUEST,
};
};
export const deleteProbeReset = () => {
return {
type: types.DELETE_PROBE_RESET,
};
}
return {
type: types.DELETE_PROBE_RESET,
};
};
export const deleteProbeSuccess = probeId => {
return {
type: types.DELETE_PROBE_SUCCESS,
payload: probeId
};
}
return {
type: types.DELETE_PROBE_SUCCESS,
payload: probeId,
};
};
export const deleteProbeError = error => {
return {
type: types.DELETE_PROBE_FAILED,
payload: error
};
}
return {
type: types.DELETE_PROBE_FAILED,
payload: error,
};
};
// Calls the API to delete a probe
export const deleteProbe = probeId => async (dispatch) => {
export const deleteProbe = probeId => async dispatch => {
dispatch(deleteProbeRequest());
dispatch(deleteProbeRequest());
try{
const response = await deleteApi(`probe/${probeId}`);
dispatch(deleteProbeSuccess(probeId));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(deleteProbeError(errors(errorMsg)));
}
}
try {
const response = await deleteApi(`probe/${probeId}`);
dispatch(deleteProbeSuccess(probeId));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(deleteProbeError(errors(errorMsg)));
}
};
//Delete project
export const addProbeRequest = () => {
return {
type: types.ADD_PROBE_REQUEST,
};
}
return {
type: types.ADD_PROBE_REQUEST,
};
};
export const addProbeReset = () => {
return {
type: types.ADD_PROBE_RESET,
};
}
return {
type: types.ADD_PROBE_RESET,
};
};
export const addProbeSuccess = probeId => {
return {
type: types.ADD_PROBE_SUCCESS,
payload: probeId
};
}
return {
type: types.ADD_PROBE_SUCCESS,
payload: probeId,
};
};
export const addProbeError = error => {
return {
type: types.ADD_PROBE_FAILED,
payload: error
};
}
return {
type: types.ADD_PROBE_FAILED,
payload: error,
};
};
export function resetAddProbe() {
return function (dispatch) {
return function(dispatch) {
dispatch(addProbeReset());
};
}
// Calls the API to add a probe
export const addProbe = (probeKey,probeName) => async (dispatch) => {
export const addProbe = (probeKey, probeName) => async dispatch => {
dispatch(addProbeRequest());
dispatch(addProbeRequest());
try{
const response = await postApi('probe/',{probeKey,probeName});
try {
const response = await postApi('probe/', { probeKey, probeName });
const data = response.data;
dispatch(addProbeSuccess(data));
return 'ok';
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(addProbeError(errors(errorMsg)));
return 'error';
}
}
dispatch(addProbeSuccess(data));
return 'ok';
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(addProbeError(errors(errorMsg)));
return 'error';
}
};

View File

@@ -1,14 +1,14 @@
import * as types from '../constants/profile';
export const showProfileMenu = () => {
return {
type: types.SHOW_PROFILE_MENU,
};
}
return {
type: types.SHOW_PROFILE_MENU,
};
};
export const hideProfileMenu = error => {
return {
type: types.HIDE_PROFILE_MENU,
payload: error
};
}
return {
type: types.HIDE_PROFILE_MENU,
payload: error,
};
};

View File

@@ -1,539 +1,532 @@
import { getApi, putApi, deleteApi, postApi } from '../api';
import * as types from '../constants/project';
import errors from '../errors'
import errors from '../errors';
// Fetch Projects
// Fetch Projects
export const fetchProjectsRequest = () => {
export const fetchProjectsRequest = () => {
return {
type: types.FETCH_PROJECTS_REQUEST,
}
}
type: types.FETCH_PROJECTS_REQUEST,
};
};
export const fetchProjectsSuccess = projects => {
export const fetchProjectsSuccess = projects => {
return {
type: types.FETCH_PROJECTS_SUCCESS,
payload: projects,
}
}
type: types.FETCH_PROJECTS_SUCCESS,
payload: projects,
};
};
export const fetchProjectsError = error => {
export const fetchProjectsError = error => {
return {
type: types.FETCH_PROJECTS_FAILURE,
payload: error,
}
}
type: types.FETCH_PROJECTS_FAILURE,
payload: error,
};
};
// Calls the API to fetch all projects.
export const fetchProjects = (skip, limit) => async (dispatch) => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
export const fetchProjects = (skip, limit) => async dispatch => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
dispatch(fetchProjectsRequest())
dispatch(fetchProjectsRequest());
try{
const response = await getApi(`project/projects/allProjects?skip=${skip}&limit=${limit}`);
try {
const response = await getApi(
`project/projects/allProjects?skip=${skip}&limit=${limit}`
);
dispatch(fetchProjectsSuccess(response.data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(fetchProjectsError(errors(errorMsg)));
}
}
dispatch(fetchProjectsSuccess(response.data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchProjectsError(errors(errorMsg)));
}
};
export const fetchProjectRequest = () => {
return {
type: types.FETCH_PROJECT_REQUEST
};
}
return {
type: types.FETCH_PROJECT_REQUEST,
};
};
export const fetchProjectSuccess = project => {
return {
type: types.FETCH_PROJECT_SUCCESS,
payload: project
};
}
return {
type: types.FETCH_PROJECT_SUCCESS,
payload: project,
};
};
export const fetchProjectError = error => {
return {
type: types.FETCH_PROJECT_FAILURE,
payload: error
};
}
return {
type: types.FETCH_PROJECT_FAILURE,
payload: error,
};
};
// Calls the API to fetch a project.
export const fetchProject = projectId => async (dispatch) => {
dispatch(fetchProjectRequest());
export const fetchProject = projectId => async dispatch => {
dispatch(fetchProjectRequest());
try{
const response = await getApi(`project/projects/${projectId}`);
const projects = response.data;
try {
const response = await getApi(`project/projects/${projectId}`);
const projects = response.data;
dispatch(fetchProjectSuccess(projects));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(fetchProjectError(errors(errorMsg)));
}
}
dispatch(fetchProjectSuccess(projects));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchProjectError(errors(errorMsg)));
}
};
export const fetchUserProjectsRequest = () => {
return {
type: types.FETCH_USER_PROJECTS_REQUEST
};
}
return {
type: types.FETCH_USER_PROJECTS_REQUEST,
};
};
export const fetchUserProjectsSuccess = users => {
return {
type: types.FETCH_USER_PROJECTS_SUCCESS,
payload: users
};
}
return {
type: types.FETCH_USER_PROJECTS_SUCCESS,
payload: users,
};
};
export const fetchUserProjectsError = error => {
return {
type: types.FETCH_USER_PROJECTS_FAILURE,
payload: error
};
}
return {
type: types.FETCH_USER_PROJECTS_FAILURE,
payload: error,
};
};
// Calls the API to fetch all user projects.
export const fetchUserProjects = (userId, skip, limit) => async (dispatch) => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
export const fetchUserProjects = (userId, skip, limit) => async dispatch => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
dispatch(fetchUserProjectsRequest());
dispatch(fetchUserProjectsRequest());
try{
const response = await getApi(`project/projects/user/${userId}?skip=${skip}&limit=${limit}`);
const users = response.data;
try {
const response = await getApi(
`project/projects/user/${userId}?skip=${skip}&limit=${limit}`
);
const users = response.data;
dispatch(fetchUserProjectsSuccess(users));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(fetchUserProjectsError(errors(errorMsg)));
}
}
dispatch(fetchUserProjectsSuccess(users));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchUserProjectsError(errors(errorMsg)));
}
};
//Delete project
export const deleteProjectRequest = () => {
return {
type: types.DELETE_PROJECT_REQUEST,
};
}
return {
type: types.DELETE_PROJECT_REQUEST,
};
};
export const deleteProjectReset = () => {
return {
type: types.DELETE_PROJECT_RESET,
};
}
return {
type: types.DELETE_PROJECT_RESET,
};
};
export const deleteProjectSuccess = project => {
return {
type: types.DELETE_PROJECT_SUCCESS,
payload: project
};
}
return {
type: types.DELETE_PROJECT_SUCCESS,
payload: project,
};
};
export const deleteProjectError = error => {
return {
type: types.DELETE_PROJECT_FAILED,
payload: error
};
}
return {
type: types.DELETE_PROJECT_FAILED,
payload: error,
};
};
// Calls the API to delete a project
export const deleteProject = projectId => async (dispatch) => {
export const deleteProject = projectId => async dispatch => {
dispatch(deleteProjectRequest());
dispatch(deleteProjectRequest());
try {
const response = await deleteApi(`project/${projectId}/deleteProject`);
const data = response.data;
try{
const response = await deleteApi(`project/${projectId}/deleteProject`);
const data = response.data;
dispatch(deleteProjectSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(deleteProjectError(errors(errorMsg)));
}
}
dispatch(deleteProjectSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(deleteProjectError(errors(errorMsg)));
}
};
//Block project
export const blockProjectRequest = () => {
return {
type: types.BLOCK_PROJECT_REQUEST,
};
}
return {
type: types.BLOCK_PROJECT_REQUEST,
};
};
export const blockProjectReset = () => {
return {
type: types.BLOCK_PROJECT_RESET,
};
}
return {
type: types.BLOCK_PROJECT_RESET,
};
};
export const blockProjectSuccess = project => {
return {
type: types.BLOCK_PROJECT_SUCCESS,
payload: project
};
}
return {
type: types.BLOCK_PROJECT_SUCCESS,
payload: project,
};
};
export const blockProjectError = error => {
return {
type: types.BLOCK_PROJECT_FAILED,
payload: error
};
}
return {
type: types.BLOCK_PROJECT_FAILED,
payload: error,
};
};
// Calls the API to block a project
export const blockProject = projectId => async (dispatch) => {
export const blockProject = projectId => async dispatch => {
dispatch(blockProjectRequest());
dispatch(blockProjectRequest());
try {
const response = await putApi(`project/${projectId}/blockProject`);
const data = response.data;
try{
const response = await putApi(`project/${projectId}/blockProject`);
const data = response.data;
dispatch(blockProjectSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(blockProjectError(errors(errorMsg)));
}
}
dispatch(blockProjectSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(blockProjectError(errors(errorMsg)));
}
};
//Renew Alert Limit
export const renewAlertLimitRequest = () => {
return {
type: types.ALERT_LIMIT_REQUEST,
};
}
return {
type: types.ALERT_LIMIT_REQUEST,
};
};
export const renewAlertLimitReset = () => {
return {
type: types.ALERT_LIMIT_RESET,
};
}
return {
type: types.ALERT_LIMIT_RESET,
};
};
export const renewAlertLimitSuccess = project => {
return {
type: types.ALERT_LIMIT_SUCCESS,
payload: project
};
}
return {
type: types.ALERT_LIMIT_SUCCESS,
payload: project,
};
};
export const renewAlertLimitError = error => {
return {
type: types.ALERT_LIMIT_FAILED,
payload: error
};
}
return {
type: types.ALERT_LIMIT_FAILED,
payload: error,
};
};
// Calls the API to block a project
export const renewAlertLimit = (projectId,alertLimit) => async (dispatch) => {
export const renewAlertLimit = (projectId, alertLimit) => async dispatch => {
dispatch(renewAlertLimitRequest());
dispatch(renewAlertLimitRequest());
try {
const response = await putApi(`project/${projectId}/renewAlertLimit`, {
alertLimit,
});
const data = response.data;
try{
const response = await putApi(`project/${projectId}/renewAlertLimit`,{alertLimit});
const data = response.data;
dispatch(renewAlertLimitSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(renewAlertLimitError(errors(errorMsg)));
}
}
dispatch(renewAlertLimitSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(renewAlertLimitError(errors(errorMsg)));
}
};
//Restore project
export const restoreProjectRequest = () => {
return {
type: types.RESTORE_PROJECT_REQUEST,
};
}
return {
type: types.RESTORE_PROJECT_REQUEST,
};
};
export const restoreProjectReset = () => {
return {
type: types.RESTORE_PROJECT_RESET,
};
}
return {
type: types.RESTORE_PROJECT_RESET,
};
};
export const restoreProjectSuccess = project => {
return {
type: types.RESTORE_PROJECT_SUCCESS,
payload: project
};
}
return {
type: types.RESTORE_PROJECT_SUCCESS,
payload: project,
};
};
export const restoreProjectError = error => {
return {
type: types.RESTORE_PROJECT_FAILED,
payload: error
};
}
return {
type: types.RESTORE_PROJECT_FAILED,
payload: error,
};
};
// Calls the API to restore a project
export const restoreProject = projectId => async (dispatch) => {
export const restoreProject = projectId => async dispatch => {
dispatch(restoreProjectRequest());
dispatch(restoreProjectRequest());
try {
const response = await putApi(`project/${projectId}/restoreProject`);
const data = response.data;
try{
const response = await putApi(`project/${projectId}/restoreProject`);
const data = response.data;
dispatch(restoreProjectSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(restoreProjectError(errors(errorMsg)));
}
}
dispatch(restoreProjectSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(restoreProjectError(errors(errorMsg)));
}
};
//Unblock project
export const unblockProjectRequest = () => {
return {
type: types.UNBLOCK_PROJECT_REQUEST,
};
}
return {
type: types.UNBLOCK_PROJECT_REQUEST,
};
};
export const unblockProjectReset = () => {
return {
type: types.UNBLOCK_PROJECT_RESET,
};
}
return {
type: types.UNBLOCK_PROJECT_RESET,
};
};
export const unblockProjectSuccess = (project) => {
return {
type: types.UNBLOCK_PROJECT_SUCCESS,
payload: project
};
}
export const unblockProjectSuccess = project => {
return {
type: types.UNBLOCK_PROJECT_SUCCESS,
payload: project,
};
};
export const unblockProjectError = (error) => {
return {
type: types.UNBLOCK_PROJECT_FAILED,
payload: error
};
}
export const unblockProjectError = error => {
return {
type: types.UNBLOCK_PROJECT_FAILED,
payload: error,
};
};
// Calls the API to un-block a project
export const unblockProject = projectId => async (dispatch) => {
export const unblockProject = projectId => async dispatch => {
dispatch(unblockProjectRequest());
dispatch(unblockProjectRequest());
try {
const response = await putApi(`project/${projectId}/unblockProject`);
const data = response.data;
try{
const response = await putApi(`project/${projectId}/unblockProject`);
const data = response.data;
dispatch(unblockProjectSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(unblockProjectError(errors(errorMsg)));
}
}
dispatch(unblockProjectSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(unblockProjectError(errors(errorMsg)));
}
};
//Add Project Notes
export const addProjectNoteRequest = () => {
return {
type: types.ADD_PROJECT_NOTE_REQUEST,
};
}
return {
type: types.ADD_PROJECT_NOTE_REQUEST,
};
};
export const addProjectNoteReset = () => {
return {
type: types.ADD_PROJECT_NOTE_RESET,
};
}
return {
type: types.ADD_PROJECT_NOTE_RESET,
};
};
export const addProjectNoteSuccess = projectNote => {
return {
type: types.ADD_PROJECT_NOTE_SUCCESS,
payload: projectNote
};
}
return {
type: types.ADD_PROJECT_NOTE_SUCCESS,
payload: projectNote,
};
};
export const addProjectNoteError = error => {
return {
type: types.ADD_PROJECT_NOTE_FAILURE,
payload: error
};
}
return {
type: types.ADD_PROJECT_NOTE_FAILURE,
payload: error,
};
};
// Calls the API to add Admin Note
export const addProjectNote = (projectId, values) => async (dispatch) => {
export const addProjectNote = (projectId, values) => async dispatch => {
dispatch(addProjectNoteRequest());
dispatch(addProjectNoteRequest());
try {
const response = await postApi(`project/${projectId}/addNote`, values);
const data = response.data;
try{
const response = await postApi(`project/${projectId}/addNote`, values);
const data = response.data;
dispatch(addProjectNoteSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(addProjectNoteError(errors(errorMsg)));
}
}
dispatch(addProjectNoteSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(addProjectNoteError(errors(errorMsg)));
}
};
//Search Projects
export const searchProjectsRequest = () => {
return {
type: types.SEARCH_PROJECTS_REQUEST,
};
}
return {
type: types.SEARCH_PROJECTS_REQUEST,
};
};
export const searchProjectsReset = () => {
return {
type: types.SEARCH_PROJECTS_RESET,
};
}
return {
type: types.SEARCH_PROJECTS_RESET,
};
};
export const searchProjectsSuccess = projects => {
return {
type: types.SEARCH_PROJECTS_SUCCESS,
payload: projects
};
}
return {
type: types.SEARCH_PROJECTS_SUCCESS,
payload: projects,
};
};
export const searchProjectsError = error => {
return {
type: types.SEARCH_PROJECTS_FAILURE,
payload: error
};
}
return {
type: types.SEARCH_PROJECTS_FAILURE,
payload: error,
};
};
// Calls the search projects api
export const searchProjects = (filter, skip, limit) => async (dispatch) => {
const values = {
filter
};
export const searchProjects = (filter, skip, limit) => async dispatch => {
const values = {
filter,
};
dispatch(searchProjectsRequest());
dispatch(searchProjectsRequest());
try{
const response = await postApi(`project/projects/search?skip=${skip}&limit=${limit}`, values);
const data = response.data;
try {
const response = await postApi(
`project/projects/search?skip=${skip}&limit=${limit}`,
values
);
const data = response.data;
dispatch(searchProjectsSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(searchProjectsError(errors(errorMsg)));
}
}
dispatch(searchProjectsSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(searchProjectsError(errors(errorMsg)));
}
};

View File

@@ -1,499 +1,497 @@
import { getApi, putApi, deleteApi, postApi } from '../api';
import * as types from '../constants/user';
import errors from '../errors'
import errors from '../errors';
export const fetchUsersRequest = () => {
return {
type: types.FETCH_USERS_REQUEST
};
}
return {
type: types.FETCH_USERS_REQUEST,
};
};
export const fetchUsersSuccess = users => {
return {
type: types.FETCH_USERS_SUCCESS,
payload: users
};
}
return {
type: types.FETCH_USERS_SUCCESS,
payload: users,
};
};
export const fetchUsersError = error => {
return {
type: types.FETCH_USERS_FAILURE,
payload: error
};
}
return {
type: types.FETCH_USERS_FAILURE,
payload: error,
};
};
// Calls the API to fetch all users.
export const fetchUsers = (skip, limit) => async (dispatch) => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
dispatch(fetchUsersRequest());
export const fetchUsers = (skip, limit) => async dispatch => {
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
dispatch(fetchUsersRequest());
try{
const response = await getApi(`user/users?skip=${skip}&limit=${limit}`);
const data = response.data;
try {
const response = await getApi(`user/users?skip=${skip}&limit=${limit}`);
const data = response.data;
dispatch(fetchUsersSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(fetchUsersError(errors(errorMsg)));
}
}
dispatch(fetchUsersSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchUsersError(errors(errorMsg)));
}
};
export const fetchUserRequest = () => {
return {
type: types.FETCH_USER_REQUEST
};
}
return {
type: types.FETCH_USER_REQUEST,
};
};
export const fetchUserSuccess = user => {
return {
type: types.FETCH_USER_SUCCESS,
payload: user
};
}
return {
type: types.FETCH_USER_SUCCESS,
payload: user,
};
};
export const fetchUserError = error => {
return {
type: types.FETCH_USER_FAILURE,
payload: error
};
}
return {
type: types.FETCH_USER_FAILURE,
payload: error,
};
};
// Calls the API to fetch a user.
export const fetchUser = userId => async (dispatch) => {
dispatch(fetchUserRequest());
try{
const response = await getApi(`user/users/${userId}`);
const data = response.data;
export const fetchUser = userId => async dispatch => {
dispatch(fetchUserRequest());
dispatch(fetchUserSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(fetchUserError(errors(errorMsg)));
}
}
try {
const response = await getApi(`user/users/${userId}`);
const data = response.data;
dispatch(fetchUserSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(fetchUserError(errors(errorMsg)));
}
};
//Update user setting
export const updateUserSettingRequest = () => {
return {
type: types.UPDATE_USER_SETTING_REQUEST
};
}
return {
type: types.UPDATE_USER_SETTING_REQUEST,
};
};
export const updateUserSettingSuccess = userSetting => {
return {
type: types.UPDATE_USER_SETTING_SUCCESS,
payload: userSetting
};
}
return {
type: types.UPDATE_USER_SETTING_SUCCESS,
payload: userSetting,
};
};
export const updateUserSettingError = error => {
return {
type: types.UPDATE_USER_SETTING_FAILURE,
payload: error
};
}
return {
type: types.UPDATE_USER_SETTING_FAILURE,
payload: error,
};
};
// Calls the API to update user setting.
export const updateUserSetting = values => async (dispatch) => {
const data = new FormData();
if (values.profilePic && values.profilePic[0]) {
data.append('profilePic', values.profilePic[0], values.profilePic[0].name);
}
export const updateUserSetting = values => async dispatch => {
const data = new FormData();
if (values.profilePic && values.profilePic[0]) {
data.append(
'profilePic',
values.profilePic[0],
values.profilePic[0].name
);
}
data.append('name', values.name);
data.append('email', values.email);
data.append('companyPhoneNumber', values.companyPhoneNumber);
data.append('timezone', values.timezone);
dispatch(updateUserSettingRequest());
data.append('name', values.name);
data.append('email', values.email);
data.append('companyPhoneNumber', values.companyPhoneNumber);
data.append('timezone', values.timezone);
dispatch(updateUserSettingRequest());
try{
const response = await putApi(`user/profile/${values._id}`, data);
const user = response.data;
try {
const response = await putApi(`user/profile/${values._id}`, data);
const user = response.data;
dispatch(updateUserSettingSuccess(user));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(updateUserSettingError(errors(errorMsg)));
}
}
dispatch(updateUserSettingSuccess(user));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(updateUserSettingError(errors(errorMsg)));
}
};
export const logFile = file => {
return function (dispatch) {
dispatch({type: 'LOG_FILE', payload: file});
};
}
return function(dispatch) {
dispatch({ type: 'LOG_FILE', payload: file });
};
};
export const resetFile = () => {
return function (dispatch) {
dispatch({type: 'RESET_FILE'});
};
}
return function(dispatch) {
dispatch({ type: 'RESET_FILE' });
};
};
//Delete user
export const deleteUserRequest = () => {
return {
type: types.DELETE_USER_REQUEST,
};
}
return {
type: types.DELETE_USER_REQUEST,
};
};
export const deleteUserReset = () => {
return {
type: types.DELETE_USER_RESET,
};
}
return {
type: types.DELETE_USER_RESET,
};
};
export const deleteUserSuccess = user => {
return {
type: types.DELETE_USER_SUCCESS,
payload: user
};
}
return {
type: types.DELETE_USER_SUCCESS,
payload: user,
};
};
export const deleteUserError = error => {
return {
type: types.DELETE_USER_FAILED,
payload: error
};
}
return {
type: types.DELETE_USER_FAILED,
payload: error,
};
};
// Calls the API to delete a user.
export const deleteUser = userId => async (dispatch) => {
dispatch(deleteUserRequest());
export const deleteUser = userId => async dispatch => {
dispatch(deleteUserRequest());
try{
const response = await deleteApi(`user/${userId}`);
const data = response.data;
try {
const response = await deleteApi(`user/${userId}`);
const data = response.data;
dispatch(deleteUserSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(deleteUserError(errors(errorMsg)));
}
}
dispatch(deleteUserSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(deleteUserError(errors(errorMsg)));
}
};
//Restore user
export const restoreUserRequest = () => {
return {
type: types.RESTORE_USER_REQUEST,
};
}
return {
type: types.RESTORE_USER_REQUEST,
};
};
export const restoreUserReset = () => {
return {
type: types.RESTORE_USER_RESET,
};
}
return {
type: types.RESTORE_USER_RESET,
};
};
export const restoreUserSuccess = user => {
return {
type: types.RESTORE_USER_SUCCESS,
payload: user
};
}
return {
type: types.RESTORE_USER_SUCCESS,
payload: user,
};
};
export const restoreUserError = error => {
return {
type: types.RESTORE_USER_FAILED,
payload: error
};
}
return {
type: types.RESTORE_USER_FAILED,
payload: error,
};
};
// Calls the API to restore a user
export const restoreUser = userId => async (dispatch) => {
dispatch(restoreUserRequest());
export const restoreUser = userId => async dispatch => {
dispatch(restoreUserRequest());
try{
const response = await putApi(`user/${userId}/restoreUser`);
const data = response.data;
try {
const response = await putApi(`user/${userId}/restoreUser`);
const data = response.data;
dispatch(restoreUserSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(restoreUserError(errors(errorMsg)));
}
}
dispatch(restoreUserSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(restoreUserError(errors(errorMsg)));
}
};
//Block user
export const blockUserRequest = () => {
return {
type: types.BLOCK_USER_REQUEST,
};
}
return {
type: types.BLOCK_USER_REQUEST,
};
};
export const blockUserReset = () => {
return {
type: types.BLOCK_USER_RESET,
};
}
return {
type: types.BLOCK_USER_RESET,
};
};
export const blockUserSuccess = user => {
return {
type: types.BLOCK_USER_SUCCESS,
payload: user
};
}
return {
type: types.BLOCK_USER_SUCCESS,
payload: user,
};
};
export const blockUserError = error => {
return {
type: types.BLOCK_USER_FAILED,
payload: error
};
}
return {
type: types.BLOCK_USER_FAILED,
payload: error,
};
};
// Calls the API to restore a user
export const blockUser = userId => async (dispatch) => {
dispatch(blockUserRequest());
export const blockUser = userId => async dispatch => {
dispatch(blockUserRequest());
try{
const response = await putApi(`user/${userId}/blockUser`);
const data = response.data;
try {
const response = await putApi(`user/${userId}/blockUser`);
const data = response.data;
dispatch(blockUserSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(blockUserError(errors(errorMsg)));
}
}
dispatch(blockUserSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(blockUserError(errors(errorMsg)));
}
};
//Unblock user
export const unblockUserRequest = () => {
return {
type: types.UNBLOCK_USER_REQUEST,
};
}
return {
type: types.UNBLOCK_USER_REQUEST,
};
};
export const unblockUserReset = () => {
return {
type: types.UNBLOCK_USER_RESET,
};
}
return {
type: types.UNBLOCK_USER_RESET,
};
};
export const unblockUserSuccess = user => {
return {
type: types.UNBLOCK_USER_SUCCESS,
payload: user
};
}
return {
type: types.UNBLOCK_USER_SUCCESS,
payload: user,
};
};
export const unblockUserError = error => {
return {
type: types.UNBLOCK_USER_FAILED,
payload: error
};
}
return {
type: types.UNBLOCK_USER_FAILED,
payload: error,
};
};
// Calls the API to unblock a user
export const unblockUser = userId => async (dispatch) => {
dispatch(unblockUserRequest());
export const unblockUser = userId => async dispatch => {
dispatch(unblockUserRequest());
try{
const response = await putApi(`user/${userId}/unblockUser`);
const data = response.data;
try {
const response = await putApi(`user/${userId}/unblockUser`);
const data = response.data;
dispatch(unblockUserSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(unblockUserError(errors(errorMsg)));
}
}
dispatch(unblockUserSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(unblockUserError(errors(errorMsg)));
}
};
//Add Project Notes
export const addUserNoteRequest = () => {
return {
type: types.ADD_USER_NOTE_REQUEST,
};
}
return {
type: types.ADD_USER_NOTE_REQUEST,
};
};
export const addUserNoteReset = () => {
return {
type: types.ADD_USER_NOTE_RESET,
};
}
return {
type: types.ADD_USER_NOTE_RESET,
};
};
export const addUserNoteSuccess = userNote => {
return {
type: types.ADD_USER_NOTE_SUCCESS,
payload: userNote
};
}
return {
type: types.ADD_USER_NOTE_SUCCESS,
payload: userNote,
};
};
export const addUserNoteError = error => {
return {
type: types.ADD_USER_NOTE_FAILURE,
payload: error
};
}
return {
type: types.ADD_USER_NOTE_FAILURE,
payload: error,
};
};
// Calls the API to add Admin Note
export const addUserNote = (userId, values) => async (dispatch) => {
dispatch(addUserNoteRequest());
export const addUserNote = (userId, values) => async dispatch => {
dispatch(addUserNoteRequest());
try{
const response = await postApi(`user/${userId}/addNote`, values);
const data = response.data;
try {
const response = await postApi(`user/${userId}/addNote`, values);
const data = response.data;
dispatch(addUserNoteSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(addUserNoteError(errors(errorMsg)));
}
}
dispatch(addUserNoteSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(addUserNoteError(errors(errorMsg)));
}
};
//Search Users
export const searchUsersRequest = () => {
return {
type: types.SEARCH_USERS_REQUEST,
};
}
return {
type: types.SEARCH_USERS_REQUEST,
};
};
export const searchUsersReset = () => {
return {
type: types.SEARCH_USERS_RESET,
};
}
return {
type: types.SEARCH_USERS_RESET,
};
};
export const searchUsersSuccess = users => {
return {
type: types.SEARCH_USERS_SUCCESS,
payload: users
};
}
return {
type: types.SEARCH_USERS_SUCCESS,
payload: users,
};
};
export const searchUsersError = error => {
return {
type: types.SEARCH_USERS_FAILURE,
payload: error
};
}
return {
type: types.SEARCH_USERS_FAILURE,
payload: error,
};
};
// Calls the search users api
export const searchUsers = (filter, skip, limit) => async (dispatch) => {
const values = {
filter
};
skip = skip ? parseInt(skip) : 0
limit = limit ? parseInt(limit) : 10
dispatch(searchUsersRequest());
export const searchUsers = (filter, skip, limit) => async dispatch => {
const values = {
filter,
};
skip = skip ? parseInt(skip) : 0;
limit = limit ? parseInt(limit) : 10;
try{
const response = await postApi(`user/users/search?skip=${skip}&limit=${limit}`, values);
const data = response.data;
dispatch(searchUsersRequest());
dispatch(searchUsersSuccess(data));
return response;
}catch(error){
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if(error && error.message){
errorMsg = error.message;
}
else{
errorMsg = 'Network Error';
}
dispatch(searchUsersError(errors(errorMsg)));
}
}
try {
const response = await postApi(
`user/users/search?skip=${skip}&limit=${limit}`,
values
);
const data = response.data;
dispatch(searchUsersSuccess(data));
return response;
} catch (error) {
let errorMsg;
if (error && error.response && error.response.data)
errorMsg = error.response.data;
if (error && error.data) {
errorMsg = error.data;
}
if (error && error.message) {
errorMsg = error.message;
} else {
errorMsg = 'Network Error';
}
dispatch(searchUsersError(errors(errorMsg)));
}
};

View File

@@ -1,10 +1,6 @@
import axios from 'axios';
import {
API_URL
} from './config';
import {
User
} from './config';
import { API_URL } from './config';
import { User } from './config';
import { history } from './store';
const baseURL = API_URL;
@@ -12,27 +8,25 @@ const Q = require('q');
const headers = {
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
Accept: 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
};
export function postApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'POST',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -49,17 +43,17 @@ export function postApi(url, data) {
export function getApi(url) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'GET',
url: `${baseURL}/${url}`,
headers
headers,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -75,21 +69,20 @@ export function getApi(url) {
return deffered.promise;
}
export function putApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'PUT',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');
@@ -107,18 +100,18 @@ export function putApi(url, data) {
export function deleteApi(url, data) {
if (User.isLoggedIn())
headers['Authorization'] = 'Basic ' + User.getAccessToken()
headers['Authorization'] = 'Basic ' + User.getAccessToken();
const deffered = Q.defer();
axios({
method: 'DELETE',
url: `${baseURL}/${url}`,
headers,
data
data,
})
.then(function (response) {
.then(function(response) {
deffered.resolve(response);
})
.catch(function (error) {
.catch(function(error) {
if (error && error.response && error.response.status === 401) {
User.clear();
history.push('/login');

View File

@@ -1,35 +1,40 @@
import React, { Component, Fragment } from 'react';
class NotFound extends Component {
render() {
return (
<Fragment>
<div className="db-World-root" >
<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
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'
NotFound.displayName = 'NotFound';
export default NotFound;

View File

@@ -3,49 +3,59 @@ import Clipboard from 'clipboard';
import PropTypes from 'prop-types';
class ClipboardWrap extends React.Component {
componentDidMount () {
const button = this.button
const input = this.input
this.clipboard = new Clipboard(
button, {
target: () => input
}
)
componentDidMount() {
const button = this.button;
const input = this.input;
this.clipboard = new Clipboard(button, {
target: () => input,
});
}
componentWillUnmount() {
this.clipboard.destroy()
this.clipboard.destroy();
}
render () {
render() {
const { value } = this.props;
return (
<div>
<input
ref={(element) => { this.input = element }}
ref={element => {
this.input = element;
}}
type={'text'}
value={value}
className="bs-TextInput"
style={{ width: 360, borderTopRightRadius: 0, borderBottomRightRadius: 0 }}
style={{
width: 360,
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
}}
readOnly
/>
<button
ref={(element) => { this.button = element }}
ref={element => {
this.button = element;
}}
className="bs-Button bs-Button--blue"
style={{ borderTopLeftRadius: 0, borderBottomLeftRadius: 0 }}
>Copy
style={{
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
}}
>
Copy
</button>
</div>
)
);
}
}
ClipboardWrap.displayName = 'ClipboardWrap';
ClipboardWrap.propTypes = {
value: PropTypes.string
}
value: PropTypes.string,
};
export default ClipboardWrap
export default ClipboardWrap;

View File

@@ -1,14 +1,12 @@
import React from 'react';
export default function (Cm){
return (props) => (
<div className="bs-BIM">
<div
className="ContextualLayer-layer--topleft ContextualLayer-layer--anytop ContextualLayer-layer--anyleft ContextualLayer-context--topleft ContextualLayer-context--anytop ContextualLayer-context--anyleft ContextualLayer-container ContextualLayer--pointerEvents"
>
<Cm {...props} />
export default function(Cm) {
return props =>
((
<div className="bs-BIM">
<div className="ContextualLayer-layer--topleft ContextualLayer-layer--anytop ContextualLayer-layer--anyleft ContextualLayer-context--topleft ContextualLayer-context--anytop ContextualLayer-context--anyleft ContextualLayer-container ContextualLayer--pointerEvents">
<Cm {...props} />
</div>
</div>
</div>
).displayName = 'ContextModal'
).displayName = 'ContextModal');
}

View File

@@ -1,12 +1,12 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import SideNav from './nav/SideNav';
import TopNav from './nav/TopNav';
import { withRouter } from 'react-router';
import ShouldRender from './basic/ShouldRender';
import ProfileMenu from './profile/ProfileMenu';
import ProfileMenu from './profile/ProfileMenu';
import ClickOutside from 'react-click-outside';
import { hideProfileMenu } from '../actions/profile';
import NotificationMenu from './notification/NotificationMenu';
@@ -14,10 +14,14 @@ import { closeNotificationMenu } from '../actions/notification';
import { fetchUsers } from '../actions/user';
export class DashboardApp extends Component {
componentDidMount() {
const { fetchUsers, ready, user } = this.props;
if (user.users && user.users.users && user.users.users.length === 0 && !user.users.requesting){
if (
user.users &&
user.users.users &&
user.users.users.length === 0 &&
!user.users.requesting
) {
fetchUsers().then(() => ready && ready());
} else {
this.props.ready && this.props.ready();
@@ -26,90 +30,123 @@ export class DashboardApp extends Component {
showProjectForm = () => {
this.props.showForm();
if(window.location.href.indexOf('localhost') <= -1){
if (window.location.href.indexOf('localhost') <= -1) {
this.context.mixpanel.track('Project Form Opened');
}
}
};
hideProfileMenu = () => {
this.props.hideProfileMenu();
if(window.location.href.indexOf('localhost') <= -1){
if (window.location.href.indexOf('localhost') <= -1) {
this.context.mixpanel.track('Profile Menu Closed');
}
}
};
closeNotificationMenu = () => {
this.props.closeNotificationMenu();
if(window.location.href.indexOf('localhost') <= -1){
if (window.location.href.indexOf('localhost') <= -1) {
this.context.mixpanel.track('Notification Menu Closed');
}
}
};
handleKeyBoard = e => {
switch (e.key) {
case 'Escape':
this.props.closeNotificationMenu();
this.props.hideProfileMenu();
return true;
default:
return false;
}
};
handleKeyBoard = (e) => {
switch(e.key){
case 'Escape':
this.props.closeNotificationMenu();
this.props.hideProfileMenu();
return true;
default:
return false;
}
}
render() {
const { user, children } = this.props
const { user, children } = this.props;
return (
<Fragment>
<ClickOutside onClickOutside={this.hideProfileMenu}>
<ProfileMenu visible={this.props.profile.menuVisible} />
</ClickOutside>
<ClickOutside onClickOutside={this.closeNotificationMenu}>
<NotificationMenu visible={this.props.notification.notificationsVisible} />
<NotificationMenu
visible={this.props.notification.notificationsVisible}
/>
</ClickOutside>
<div onKeyDown={this.handleKeyBoard} className="db-World-root" >
<ShouldRender if={!user.users.requesting && user.users.success}>
<div onKeyDown={this.handleKeyBoard} className="db-World-root">
<ShouldRender
if={!user.users.requesting && user.users.success}
>
<div className="db-World-wrapper Box-root Flex-flex Flex-direction--column">
<SideNav />
<div className="db-World-mainPane Box-root Padding-right--20" >
<div className="db-World-mainPane Box-root Padding-right--20">
{children}
</div>
<TopNav />
</div>
</ShouldRender>
<ShouldRender if={user.users.requesting}>
<div id="app-loading" style={{ 'position': 'fixed', 'top': '0', 'bottom': '0', 'left': '0', 'right': '0', 'zIndex': '999', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center' }}>
<div style={{ 'transform': 'scale(2)' }}>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" className="bs-Spinner-svg">
<ellipse cx="12" cy="12" rx="10" ry="10" className="bs-Spinner-ellipse"></ellipse>
</svg>
</div>
<div
id="app-loading"
style={{
position: 'fixed',
top: '0',
bottom: '0',
left: '0',
right: '0',
zIndex: '999',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<div style={{ transform: 'scale(2)' }}>
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="bs-Spinner-svg"
>
<ellipse
cx="12"
cy="12"
rx="10"
ry="10"
className="bs-Spinner-ellipse"
></ellipse>
</svg>
</div>
</ShouldRender>
<ShouldRender if={user.users.error}>
<div id="app-loading" style={{ 'backgroundColor':'#E6EBF1', 'position': 'fixed', 'top': '0', 'bottom': '0', 'left': '0', 'right': '0', 'zIndex': '999', 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center' }}>
<div>Cannot connect to server.</div>
</div>
</ShouldRender>
</div>
</ShouldRender>
<ShouldRender if={user.users.error}>
<div
id="app-loading"
style={{
backgroundColor: '#E6EBF1',
position: 'fixed',
top: '0',
bottom: '0',
left: '0',
right: '0',
zIndex: '999',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<div>Cannot connect to server.</div>
</div>
</ShouldRender>
</div>
</Fragment>
)
);
}
}
DashboardApp.displayName = 'DashboardApp'
DashboardApp.displayName = 'DashboardApp';
DashboardApp.propTypes = {
profile: PropTypes.object.isRequired,
@@ -120,25 +157,29 @@ DashboardApp.propTypes = {
fetchUsers: PropTypes.func,
children: PropTypes.any,
ready: PropTypes.func,
user: PropTypes.object.isRequired
}
user: PropTypes.object.isRequired,
};
const mapStateToProps = state => ({
profile: state.profileSettings,
notification: state.notifications,
user: state.user
})
user: state.user,
});
const mapDispatchToProps = dispatch => (
bindActionCreators({
hideProfileMenu,
closeNotificationMenu,
fetchUsers
}, dispatch)
)
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
hideProfileMenu,
closeNotificationMenu,
fetchUsers,
},
dispatch
);
DashboardApp.contextTypes = {
mixpanel: PropTypes.object.isRequired
mixpanel: PropTypes.object.isRequired,
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DashboardApp));
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(DashboardApp)
);

View File

@@ -1,14 +1,16 @@
import React from 'react';
function DataPathHoC(WrappedComponent, data) {
return class extends React.Component {
static displayName = 'HocCom';
render() {
// Wraps the input component in a container, without mutating it. Good!
return <WrappedComponent {...this.props} webhook={data} data={data} />;
}
}
return class extends React.Component {
static displayName = 'HocCom';
render() {
// Wraps the input component in a container, without mutating it. Good!
return (
<WrappedComponent {...this.props} webhook={data} data={data} />
);
}
};
}
DataPathHoC.displayName = 'DataPathHoC';
export default DataPathHoC
export default DataPathHoC;

View File

@@ -1,43 +1,49 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
const composableComponent = (ComposedComponent) => {
const composableComponent = ComposedComponent => {
class Modal extends Component {
constructor(props){
constructor(props) {
super(props);
this.props = props;
this.onClose = this.onClose.bind(this);
this.onConfirm = this.onConfirm.bind(this);
}
onClose =(value)=> {
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)=> {
};
onConfirm = value => {
const _this = this;
if (this.props.item.onConfirm) {
this.props.item.onConfirm(value)
.then(() => _this.props.onClose(_this.props.item),
()=> {})
this.props.item.onConfirm(value).then(
() => _this.props.onClose(_this.props.item),
() => {}
);
} else {
this.props.onClose(this.props.item)
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'};
const modalContainerStyle = {
overflowX: 'auto',
overflowY: 'scroll',
display: 'block',
top: '0px',
};
return (
<div
className={mainClass}
style={{
zIndex: (zIndex + 1) * 10000
zIndex: (zIndex + 1) * 10000,
}}
>
<div
@@ -47,12 +53,17 @@ const composableComponent = (ComposedComponent) => {
opacity: 1,
transform: 'none',
display: 'block',
pointerEvents: 'auto'
pointerEvents: 'auto',
}}
>
<div className="modal_container" style={modalContainerStyle}>
<ComposedComponent closeThisDialog={this.onClose} confirmThisDialog={this.onConfirm} />
<div
className="modal_container"
style={modalContainerStyle}
>
<ComposedComponent
closeThisDialog={this.onClose}
confirmThisDialog={this.onConfirm}
/>
</div>
</div>
</div>
@@ -62,15 +73,14 @@ const composableComponent = (ComposedComponent) => {
Modal.propTypes = {
onConfirm: PropTypes.func,
item: PropTypes.object.isRequired,
onClose:PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
extraClasses: PropTypes.string,
zIndex: PropTypes.number.isRequired
}
zIndex: PropTypes.number.isRequired,
};
Modal.displayName = 'Modal'
Modal.displayName = 'Modal';
return Modal;
}
};
export default composableComponent;
export default composableComponent;

View File

@@ -1,25 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
/**
* @function Modalize
* @param {React.Props} props Props comprise an object with 3 JSX values for `HEADER`, `CONTENT` & `FOOTER`
* @returns {JSX.Element} A modal and a child component.
*/
*/
export function Modalize({ HEADER, CONTENT, FOOTER }) {
return HEADER && CONTENT && FOOTER ? (
<div className="ModalLayer-wash Box-root Flex-flex Flex-alignItems--flexStart Flex-justifyContent--center">
<div className="ModalLayer-contents" tabIndex="-1" style={{marginTop: 105}}>
<div
className="ModalLayer-contents"
tabIndex="-1"
style={{ marginTop: 105 }}
>
<div className="bs-BIM">
<form>
<div className="bs-Modal bs-Modal--medium">
<div className="bs-Modal-header">
<div className="bs-Modal-header-copy">
{HEADER}
@@ -27,38 +25,29 @@ export function Modalize({ HEADER, CONTENT, FOOTER }) {
<div className="bs-Modal-messages"></div>
</div>
<div className="bs-Modal-content">
{CONTENT}
</div>
<div className="bs-Modal-footer">
{FOOTER}
</div>
<div className="bs-Modal-content">{CONTENT}</div>
<div className="bs-Modal-footer">{FOOTER}</div>
</div>
</form>
</form>
</div>
</div>
</div>
) : null;
) : null;
}
const mapStateToProps = state => ({
HEADER: state.modal.header,
CONTENT: state.modal.content,
FOOTER: state.modal.footer
})
FOOTER: state.modal.footer,
});
Modalize.propTypes = {
HEADER: PropTypes.string.isRequired,
CONTENT: PropTypes.string.isRequired,
FOOTER: PropTypes.string.isRequired
}
FOOTER: PropTypes.string.isRequired,
};
Modalize.displayName = 'Modalize'
Modalize.displayName = 'Modalize';
export default connect(mapStateToProps)(Modalize);
export default connect(mapStateToProps)(Modalize);

View File

@@ -3,37 +3,37 @@ import { connect } from 'react-redux';
import { User } from '../config';
import { history } from '../store';
export default function (ComposedComponent) {
class NotAuthentication extends Component {
constructor(props) {
super(props);
this.props = props;
export default function(ComposedComponent) {
class NotAuthentication extends Component {
constructor(props) {
super(props);
this.props = props;
this.isAuthenticated = User.isLoggedIn();
this.isAuthenticated = User.isLoggedIn();
}
componentDidMount() {
if (this.isAuthenticated) {
history.push('/project/project/monitoring');
}
}
componentDidUpdate() {
if (this.isAuthenticated) {
history.push('/project/project/monitoring');
}
}
render() {
return <ComposedComponent {...this.props} />;
}
}
componentDidMount() {
if (this.isAuthenticated) {
history.push('/project/project/monitoring');
}
function mapStateToProps(state_Ignored) {
return {};
}
componentDidUpdate() {
if (this.isAuthenticated) {
history.push('/project/project/monitoring');
}
}
NotAuthentication.displayName = 'NotAuthentication';
render() {
return <ComposedComponent {...this.props} />;
}
}
function mapStateToProps(state_Ignored) {
return {};
}
NotAuthentication.displayName = 'NotAuthentication'
return connect(mapStateToProps)(NotAuthentication);
}
return connect(mapStateToProps)(NotAuthentication);
}

View File

@@ -8,42 +8,46 @@ export default (ComposedComponent, extras) => {
class OutsideCkick extends Component {
constructor(props) {
super(props);
this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
/**
* Set the wrapper ref
*/
setWrapperRef(node) {
this.wrapperRef = node;
}
/**
* Alert if clicked on outside of element
*/
handleClickOutside =(event)=> {
handleClickOutside = event => {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
extras.closeModal();
}
}
render(){
return <div ref={this.setWrapperRef}> <ComposedComponent {...this.props} /> </div>
};
render() {
return (
<div ref={this.setWrapperRef}>
{' '}
<ComposedComponent {...this.props} />{' '}
</div>
);
}
}
OutsideCkick.displayName = 'PublicPage'
return OutsideCkick
}
OutsideCkick.displayName = 'PublicPage';
return OutsideCkick;
};

View File

@@ -5,21 +5,21 @@ import routes from '../routes';
const { allRoutes } = routes;
const PublicPage = () => (
<Switch>
{allRoutes
.filter(route => route.isPublic)
.map((route, index) => (
<Route
component={route.component}
exact={route.exact}
path={route.path}
key={index}
/>
))}
<Redirect to='/login' />
</Switch>
<Switch>
{allRoutes
.filter(route => route.isPublic)
.map((route, index) => (
<Route
component={route.component}
exact={route.exact}
path={route.path}
key={index}
/>
))}
<Redirect to="/login" />
</Switch>
);
PublicPage.displayName = 'PublicPage'
PublicPage.displayName = 'PublicPage';
export default PublicPage;

View File

@@ -4,50 +4,53 @@ import PropTypes from 'prop-types';
import { User } from '../config';
import { history } from '../store';
export default function (ComposedComponent) {
class Authentication extends Component {
export default function(ComposedComponent) {
class Authentication extends Component {
constructor(props) {
super(props);
this.props = props;
constructor(props){
super(props);
this.props = props;
this.isAuthenticated = User.isLoggedIn();
}
this.isAuthenticated = User.isLoggedIn();
componentDidMount() {
if (!this.isAuthenticated) {
history.push('/login', {
continue: this.props.location.pathname,
});
}
}
componentDidUpdate() {
if (!this.isAuthenticated) {
history.push('/login', {
continue: this.props.location.pathname,
});
}
}
PropTypes = {
router: PropTypes.object,
};
render() {
return <ComposedComponent {...this.props} />;
}
}
componentDidMount() {
if (!this.isAuthenticated) {
history.push('/login', { continue: this.props.location.pathname });
}
Authentication.propTypes = {
location: PropTypes.object,
};
Authentication.displayName = 'RequireAuth';
function mapStateToProps(state_Ignored) {
return {};
}
componentDidUpdate() {
if (!this.isAuthenticated) {
history.push('/login', { continue: this.props.location.pathname });
}
function mapDispatchToProps(dispatch_Ignored) {
return {};
}
PropTypes = {
router: PropTypes.object
}
render() {
return <ComposedComponent {...this.props} />;
}
}
Authentication.propTypes = {
location: PropTypes.object
}
Authentication.displayName = 'RequireAuth'
function mapStateToProps(state_Ignored) {
return {};
}
function mapDispatchToProps (dispatch_Ignored) {
return {};
}
return connect(mapStateToProps, mapDispatchToProps)(Authentication);
return connect(mapStateToProps, mapDispatchToProps)(Authentication);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import ShouldRender from '../basic/ShouldRender';
import { Field } from 'redux-form';
const AdminNote = ({ fields, meta: { error, submitFailed } }) => {
return (
<ul>
{
fields.map((val, i) => {
return (
<li key={i}>
<div className="bs-Fieldset-row">
<label className="bs-Fieldset-label">Admin Note</label>
<div className="bs-Fieldset-fields bs-Fieldset-fields--wide">
<Field
id={`txtAdminNote${i}`}
rows="5"
cols="100"
className="bs-TextArea"
type="text"
name={`${val}.note`}
component="textarea"
/>
</div>
{fields.map((val, i) => {
return (
<li key={i}>
<div className="bs-Fieldset-row">
<label className="bs-Fieldset-label">
Admin Note
</label>
<div className="bs-Fieldset-fields bs-Fieldset-fields--wide">
<Field
id={`txtAdminNote${i}`}
rows="5"
cols="100"
className="bs-TextArea"
type="text"
name={`${val}.note`}
component="textarea"
/>
</div>
</div>
<div className="bs-Fieldset-row">
<label className="bs-Fieldset-label"></label>
<div className="bs-Fieldset-fields">
<div className="Box-root Flex-flex Flex-alignItems--center">
<button
id={`btnRemoveAdminNote${i}`}
className="bs-Button bs-DeprecatedButton"
type="button"
onClick={() => fields.remove(i)}
>
Remove
</button>
</div>
<div className="bs-Fieldset-row">
<label className="bs-Fieldset-label"></label>
<div className="bs-Fieldset-fields">
<div className="Box-root Flex-flex Flex-alignItems--center">
<button
id={`btnRemoveAdminNote${i}`}
className="bs-Button bs-DeprecatedButton"
type="button"
onClick={() => fields.remove(i)}
>
Remove
</button>
</div>
</div>
</div>
</li>
)
})
}
</div>
</div>
</li>
);
})}
<li>
<div className="bs-Fieldset-row">
@@ -52,41 +50,34 @@ const AdminNote = ({ fields, meta: { error, submitFailed } }) => {
<div className="bs-Fieldset-fields">
<div className="Box-root Flex-flex Flex-alignItems--center">
<div>
<button
id="btnAddAdminNotes"
type="button"
className="bs-Button bs-FileUploadButton bs-Button--icon bs-Button--new"
onClick={() => fields.push({note: ''})}
>
Add Notes
</button>
<ShouldRender if={submitFailed && error}>
<span>{error}</span>
</ShouldRender>
<button
id="btnAddAdminNotes"
type="button"
className="bs-Button bs-FileUploadButton bs-Button--icon bs-Button--new"
onClick={() => fields.push({ note: '' })}
>
Add Notes
</button>
<ShouldRender if={submitFailed && error}>
<span>{error}</span>
</ShouldRender>
</div>
</div>
<p className="bs-Fieldset-explanation">
<span>
You can add any number of notes.
</span>
<span>You can add any number of notes.</span>
</p>
</div>
</div>
</li>
</ul>
)
}
);
};
AdminNote.displayName = 'AdminNote'
AdminNote.displayName = 'AdminNote';
AdminNote.propTypes = {
meta: PropTypes.object.isRequired,
fields: PropTypes.oneOfType([
PropTypes.array,
PropTypes.object
]).isRequired,
}
fields: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
};
export {AdminNote}
export { AdminNote };

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { FormLoader } from '../basic/Loader';
@@ -15,18 +15,17 @@ function validate(values) {
if (values.adminNotes) {
for (let i = 0; i < values.adminNotes.length; i++) {
const adminNotesErrors = {}
const adminNotesErrors = {};
if (values.adminNotes[i] && values.adminNotes[i].note) {
if (!Validate.text(values.adminNotes[i].note)) {
adminNotesErrors.note = 'Note is not in text format.'
adminNotesArrayErrors[i] = adminNotesErrors
adminNotesErrors.note = 'Note is not in text format.';
adminNotesArrayErrors[i] = adminNotesErrors;
}
}
}
if (adminNotesArrayErrors.length) {
errors.adminNotes = adminNotesArrayErrors
errors.adminNotes = adminNotesArrayErrors;
}
}
@@ -34,13 +33,12 @@ function validate(values) {
}
export class AdminNotes extends Component {
submitForm = async (values) => {
submitForm = async values => {
await this.props.addNote(this.props.id, values.adminNotes);
if (window.location.href.indexOf('localhost') <= -1) {
this.context.mixpanel.track('Admin Notes Updated', values);
}
}
};
render() {
const { handleSubmit, requesting } = this.props;
@@ -53,7 +51,9 @@ export class AdminNotes extends Component {
<span className="Text-color--inherit Text-display--inline Text-fontSize--16 Text-fontWeight--medium Text-lineHeight--24 Text-typeface--base Text-wrap--wrap">
<span>Admin Notes</span>
</span>
<p><span>Leave a comment.</span></p>
<p>
<span>Leave a comment.</span>
</p>
</div>
</div>
<form onSubmit={handleSubmit(this.submitForm)}>
@@ -62,9 +62,9 @@ export class AdminNotes extends Component {
<div className="bs-Fieldset-wrapper Box-root Margin-bottom--2">
<fieldset className="bs-Fieldset">
<div className="bs-Fieldset-rows">
<FieldArray
name="adminNotes"
component={ AdminNote }
<FieldArray
name="adminNotes"
component={AdminNote}
/>
</div>
</fieldset>
@@ -72,50 +72,49 @@ export class AdminNotes extends Component {
</div>
</div>
<div className="bs-ContentSection-footer bs-ContentSection-content Box-root Box-background--white Flex-flex Flex-alignItems--center Flex-justifyContent--spaceBetween Padding-horizontal--20 Padding-vertical--12">
<span className="db-SettingsForm-footerMessage"></span>
<div>
<button
className="bs-Button bs-DeprecatedButton bs-Button--blue"
disabled={requesting}
type="submit">
<ShouldRender if={requesting}>
<FormLoader />
</ShouldRender>
<ShouldRender if={!requesting}>
<span>Save</span>
</ShouldRender>
</button>
<span className="db-SettingsForm-footerMessage"></span>
<div>
<button
className="bs-Button bs-DeprecatedButton bs-Button--blue"
disabled={requesting}
type="submit"
>
<ShouldRender if={requesting}>
<FormLoader />
</ShouldRender>
<ShouldRender if={!requesting}>
<span>Save</span>
</ShouldRender>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
)
);
}
}
AdminNotes.displayName = 'AdminNotes'
AdminNotes.displayName = 'AdminNotes';
const mapDispatchToProps = dispatch => bindActionCreators(
{ }
, dispatch);
const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
const mapStateToProps = state_Ignored => {
return {};
}
};
AdminNotes.propTypes = {
requesting: PropTypes.bool,
addNote: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
handleSubmit: PropTypes.func
}
handleSubmit: PropTypes.func,
};
const AdminNotesForm = reduxForm({
form: 'AdminNotes', // a unique identifier for this form
validate, // <--- validation function given to redux-for
enableReinitialize: true
enableReinitialize: true,
})(AdminNotes);
export default connect(mapStateToProps, mapDispatchToProps)(AdminNotesForm);

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