mirror of
https://github.com/responsively-org/responsively-app
synced 2024-11-10 14:54:12 +00:00
Code cleanup - App
This commit is contained in:
parent
5ed73eb41e
commit
049f378d0f
9 changed files with 4 additions and 621 deletions
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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) {}
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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.',
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue