Code cleanup - App

This commit is contained in:
Manoj Vivek 2020-01-30 17:32:19 +05:30
parent 5ed73eb41e
commit 049f378d0f
9 changed files with 4 additions and 621 deletions

View file

@ -1,6 +1,4 @@
{
"NODE_ENV": "development",
"REST_BASE_URL": "https://n7mfai4l76.execute-api.us-east-1.amazonaws.com/dev/",
"WEBSOCKET_URL": "wss://imlxkwukq5.execute-api.us-east-1.amazonaws.com/dev/",
"START_HOT": "1"
}

View file

@ -1,5 +1,3 @@
{
"NODE_ENV": "production",
"REST_BASE_URL": "https://n7mfai4l76.execute-api.us-east-1.amazonaws.com/",
"WEBSOCKET_URL": "wss://imlxkwukq5.execute-api.us-east-1.amazonaws.com/"
"NODE_ENV": "production"
}

View file

@ -1,227 +0,0 @@
// @flow
import React, {useState} from 'react';
import url from 'url';
import {validateEmail} from '../../../utils/generalUtils';
import {shell} from 'electron';
import path from 'path';
import cx from 'classnames';
import styles from './style.css';
import {saveLicenseKey, validateLicenseKey} from '../../../utils/licenseUtils';
import {DEACTIVATION_REASON} from '../../../constants/license';
export default function WelcomeScreen(props) {
const [activeSection, setActiveSection] = useState('license');
const [licenseKey, setLicenseKey] = useState(props.licenseKey);
const [trialEmail, setTrialEmail] = useState('');
const [trialActivationStatus, setTrialActivationStatus] = useState('');
const [
trialActivationErrorMessage,
setTrialActivationErrorMessage,
] = useState('');
const [licenseActivationStatus, setLicenseActivationStatus] = useState('');
const [
licenseActivationErrorMessage,
setLicenseActivationErrorMessage,
] = useState('');
const isLicenseActive = activeSection === 'license';
const isTrialActive = activeSection === 'trial';
const trialEmailChange = e => {
setTrialEmail(e.target.value);
setTrialActivationStatus('');
setTrialActivationErrorMessage('');
};
const licenseKeyChange = e => {
setLicenseKey(e.target.value);
setLicenseActivationStatus('');
setLicenseActivationErrorMessage('');
};
const activateTrial = async () => {
if (!validateEmail(trialEmail)) {
setTrialActivationStatus('false');
setTrialActivationErrorMessage(
'Invalid email address, please enter a valid one to proceed'
);
return;
}
setTrialActivationStatus('loading');
try {
const response = await fetch(
`${path.join(
process.env.REST_BASE_URL,
'/activate-trial'
)}?email=${trialEmail}`
);
const body = await response.json();
console.log('activating trial', body);
if (body.status) {
setTrialActivationStatus('true');
} else {
setTrialActivationStatus('false');
setTrialActivationErrorMessage('Trial activation failed');
}
} catch (err) {
setTrialActivationStatus('false');
setTrialActivationErrorMessage('Trial activation failed');
}
};
const activateLicense = async () => {
console.log('activate license', licenseKey);
setLicenseActivationStatus('loading');
const {status, reason} = await validateLicenseKey(licenseKey);
console.log('response', {status, reason});
setLicenseActivationStatus(status.toString());
setLicenseActivationErrorMessage(reason);
if (status) {
saveLicenseKey(licenseKey);
setTimeout(props.onActivation, 2000);
}
};
const getMainTitle = () => {
switch (props.reason) {
case DEACTIVATION_REASON.REVALIDATION:
return 'Sorry, we need to re-validate the license key';
default:
return 'Welcome, lets activate the app';
}
};
alert('process.env.REST_BASE_URL', process.env.REST_BASE_URL);
return (
<div className={styles.container}>
<div className={styles.title}>{getMainTitle()}</div>
<div className={styles.mainSection}>
<div
className={cx(styles.mainSectionBlock, {
[styles.active]: isLicenseActive,
})}
onMouseEnter={() => setActiveSection('license')}
>
<div className={styles.subTitle}>Enter license key</div>
<div>
<div className={styles.desc}>
Please enter the license key that you have recieved on your email
</div>
<div
className={cx(styles.inputContainer, {
[styles.active]: isLicenseActive,
})}
>
<i className={cx(styles.inputIcon, 'fa fa-lock')} />
<input
className={cx(styles.inputField, styles.licenseField)}
autoFocus
type="text"
placeholder="License key"
value={licenseKey}
onChange={licenseKeyChange}
/>
<span
className={cx(styles.inputIcon, styles.iconButton, {
'fa fa-arrow-right': licenseActivationStatus !== 'loading',
'fa fa-circle-notch spin':
licenseActivationStatus === 'loading',
})}
onClick={activateLicense}
/>
</div>
<div>
{licenseActivationStatus === 'false' &&
licenseActivationErrorMessage && (
<div className={styles.errorMessage}>
{licenseActivationErrorMessage}
</div>
)}
{licenseActivationStatus === 'true' && (
<div className={styles.successMessage}>
License key validation successful, please wait a moment.{' '}
<span className="fa fa-circle-notch spin" />
</div>
)}
</div>
<div
className={cx(styles.buyLicenseContainer, {
[styles.active]: isLicenseActive,
})}
>
<div className={cx(styles.desc, styles.afterDesc)}>
Don't have a license key? Buy one from here.
</div>
<div
className={styles.buyLicenseButton}
onClick={() =>
shell.openExternal('https://responsively.app#pricing')
}
>
Buy License
</div>
</div>
</div>
</div>
<div className={styles.sectionDividerContainer}>
<div className={styles.sectionDivider}>
<div className={styles.sectionDividerLine} />
{/*<div className={styles.orText}>OR</div>
<div className={styles.sectionDividerLine} />*/}
</div>
</div>
<div
className={cx(styles.mainSectionBlock, {
[styles.active]: isTrialActive,
})}
onMouseEnter={() => setActiveSection('trial')}
>
<div className={styles.subTitle}>Activate trial</div>
<div>
<div className={styles.desc}>
Please enter your email address to activate free trial
</div>
<div
className={cx(styles.inputContainer, {
[styles.active]: isTrialActive,
})}
>
<input
className={cx(styles.inputField)}
type="text"
placeholder="Email address"
name="email"
value={trialEmail}
onChange={trialEmailChange}
/>
<span
className={cx(styles.inputIcon, styles.iconButton, {
'fa fa-arrow-right': trialActivationStatus !== 'loading',
'fa fa-circle-notch spin':
trialActivationStatus === 'loading',
})}
onClick={activateTrial}
/>
</div>
<div>
{trialActivationStatus === 'false' &&
trialActivationErrorMessage && (
<div className={styles.errorMessage}>
{trialActivationErrorMessage}
</div>
)}
{trialActivationStatus === 'true' && (
<div className={styles.successMessage}>
Trial Activated, please check your email for the trial license
key
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
}

View file

@ -1,183 +0,0 @@
.container {
margin: 100px;
--activeButtonBg: #fd2d55;
--inactiveButtonBg: #9e1d35 /*#be2240 #ff93a8*/;
--activeColor: white;
--inactiveColor: lightgrey;
}
.title {
font-size: 4.5rem;
font-weight: 600;
text-align: center;
margin-bottom: 50px;
animation: shake 0.6s ease-in-out;
}
@keyframes shake {
10%,
90% {
transform: translate3d(-1px, 0, 0);
}
20%,
80% {
transform: translate3d(4px, 0, 0);
}
30%,
50%,
70% {
transform: translate3d(-10px, 0, 0);
}
40%,
60% {
transform: translate3d(10px, 0, 0);
}
}
.subTitle {
font-size: 2.5rem;
font-weight: 200;
text-align: center;
margin-bottom: 100px;
}
.mainSection {
display: flex;
}
.mainSectionBlock {
position: relative;
padding: 50px;
width: 50%;
height: 600px;
color: var(--inactiveColor);
z-index: 2;
}
.mainSectionBlock.active {
color: var(--activeColor);
}
.sectionDividerContainer {
position: relative;
}
.sectionDivider {
display: flex;
align-items: center;
font-size: 2rem;
flex-direction: column;
position: absolute;
height: 100%;
width: 42px;
transform: translateX(-21px);
}
.orText {
margin: 10px 0;
color: var(--inactiveColor);
}
.sectionDividerLine {
content: '';
z-index: -1;
top: 0;
bottom: 0;
left: 50%;
border-left: 1px solid var(--inactiveColor);
transform: translate(-50%);
height: 100% /*45%*/;
}
.inputContainer {
display: flex;
width: 100%;
margin: 20px 0;
box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.75);
}
.inputIcon {
padding: 10px;
background: var(--inactiveButtonBg);
color: var(--inactiveColor);
min-width: 50px;
text-align: center;
display: flex !important;
align-items: center;
justify-content: center;
}
.inputField {
width: 100%;
padding: 10px;
outline: none;
font-size: 1.5rem;
border: 2px solid var(--inactiveColor);
background: var(--inactiveColor);
}
.licenseField {
font-family: monospace;
font-size: 1.75rem;
}
.inputContainer.active .inputIcon {
color: var(--activeColor);
background: var(--activeButtonBg);
}
.inputContainer.active .inputField {
background: var(--activeColor);
border: 2px solid var(--activeColor);
}
.iconButton {
cursor: pointer;
}
.desc {
margin: 10px 0 20px;
font-size: 1.25rem;
}
.buyLicenseContainer {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
color: var(--inactiveColor);
}
.buyLicenseContainer.active {
color: var(--activeColor);
}
.afterDesc {
color: var(--inactiveColor);
text-align: center;
margin-top: 50px;
}
.buyLicenseButton {
width: fit-content;
text-transform: capitalize;
background: var(--inactiveButtonBg);
padding: 10px 30px;
font-size: 1.25rem;
cursor: pointer;
}
.buyLicenseContainer.active .buyLicenseButton {
background: var(--activeButtonBg);
}
.errorMessage {
color: red;
}
.successMessage {
color: green;
}

View file

@ -1,109 +0,0 @@
import React from 'react';
import WelcomeScreen from './WelcomeScreen';
import Spinner from '../Spinner';
import styles from './style.css';
import {getLicensekey, validateLicenseKey} from '../../utils/licenseUtils';
import {initWS, cleanUp} from './ws';
import {DEACTIVATION_REASON} from '../../constants/license';
const LICENSE_STATUS = {
VALIDATING: 'VALIDATING',
VALID: 'VALID',
INVALID: 'INVALID',
};
export default class LicenseManager extends React.Component {
constructor(props) {
super(props);
this.state = {
status: LICENSE_STATUS.VALIDATING,
deactivationReason: null,
};
}
componentDidMount() {
this.init();
}
componentWillUnmount() {
this.cleanUpState();
}
init = async () => {
const {status} = await validateLicenseKey(getLicensekey());
if (!status) {
return this.setState({status: LICENSE_STATUS.INVALID});
}
this.onActivation();
};
initializeWS = () => {
try {
const {socket, sendMessage} = initWS(
`${process.env.WEBSOCKET_URL}?licenseKey=${getLicensekey()}`,
this.onWSMessage
);
this.sendMessage = sendMessage;
this.socket = socket;
this.setState({status: LICENSE_STATUS.VALID});
this.intervalHandle = setInterval(this.periodicPing, 20000);
} catch (err) {
console.log('err', err);
}
};
periodicPing = () => {
this.sendMessage('validate', {
licenseKey: getLicensekey(),
});
};
onWSMessage = (type, message) => {
if (type === 'validate_response') {
if (!message.status) {
this.deactivate();
}
}
};
deactivate = () => {
this.cleanUpState();
this.setState({
status: LICENSE_STATUS.INVALID,
deactivationReason: DEACTIVATION_REASON.REVALIDATION,
});
};
cleanUpState = () => {
cleanUp(this.socket);
this.socket = null;
this.sendMessage = null;
this.intervalHandle &&
window.clearInterval(this.intervalHandle) &&
(this.intervalHandle = null);
};
onActivation = () => {
this.setState({status: LICENSE_STATUS.VALID, deactivationReason: null});
this.initializeWS();
};
render() {
if (this.state.status === LICENSE_STATUS.VALIDATING) {
return <Spinner size={50} />;
}
if (this.state.status === LICENSE_STATUS.VALID) {
return this.props.children;
}
return (
<WelcomeScreen
onActivation={this.onActivation}
reason={this.state.deactivationReason}
licenseKey={getLicensekey()}
/>
);
}
}

View file

@ -1,41 +0,0 @@
import WebSocket from 'isomorphic-ws';
export function initWS(url, onMessage) {
let isOpen = false;
const socket = new WebSocket(url);
socket.onopen = () => {
console.log('WS open');
isOpen = true;
};
socket.onclose = () => {
console.log('WS close');
isOpen = false;
};
const sendMessage = (action, data) => {
if (!isOpen) {
console.log('WS connection not open', socket.readyState);
throw new Error('WS connection not open', socket.readyState);
}
socket.send(JSON.stringify({action, data}));
};
socket.onmessage = ({data: messageString}) => {
console.log('newMessage', messageString);
const message = JSON.parse(messageString);
const {action, data} = message;
onMessage(action, data);
};
return {socket, sendMessage};
}
export function cleanUp(socketInstance) {
if (!socketInstance) {
return;
}
if (socketInstance.readyState === 1) {
socketInstance.close();
}
}
export function destroyWS(ws) {}

View file

@ -8,7 +8,6 @@ import Routes from '../Routes';
import {createMuiTheme, makeStyles} from '@material-ui/core/styles';
import {ThemeProvider} from '@material-ui/styles';
import {grey} from '@material-ui/core/colors';
import LicenseManager from '../components/LicenseManager';
import {themeColor} from '../constants/colors';
import ErrorBoundary from '../components/ErrorBoundary';
@ -40,11 +39,9 @@ const getApp = history => {
if (true || process.env.NODE_ENV !== 'development') {
return (
<ErrorBoundary>
<LicenseManager>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</LicenseManager>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</ErrorBoundary>
);
}

View file

@ -1,50 +0,0 @@
import settings from 'electron-settings';
import path from 'path';
const LICENSE_KEY = 'LICENSE_KEY';
export function saveLicenseKey(key) {
settings.set(LICENSE_KEY, key);
}
export function getLicensekey() {
return settings.get(LICENSE_KEY);
}
export async function validateLicenseKey(licenseKey) {
if (!licenseKey) {
return {
status: false,
reason: 'License key cannot be empty, please enter a valid one.',
};
}
try {
console.log(
`${path.join(
process.env.REST_BASE_URL,
'/validate-license'
)}?licenseKey=${licenseKey}`
);
alert(`URL changed: ${process.env.REST_BASE_URL}`);
const responseBody = await fetch(
`${path.join(
process.env.REST_BASE_URL,
'/validate-license'
)}?licenseKey=${licenseKey}`
).then(response => response.json());
if (responseBody.status) {
return {status: true};
} else {
return {
status: false,
reason: 'Not a valid license key, please verify the key and try again.',
};
}
} catch (err) {
console.log('Error', err);
return {
status: false,
reason: 'Unable to validate the license key, please try again.',
};
}
}