Skip to content

Commit

Permalink
Merge pull request #4 from SailingSteve/steveWeConnectDec14-153pm
Browse files Browse the repository at this point in the history
New Login page to login via api to weconnect_server
  • Loading branch information
DaleMcGrew authored Dec 14, 2024
2 parents 179b246 + c65af9b commit 7cdaf19
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 16 deletions.
10 changes: 10 additions & 0 deletions WeVotePorts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#### Ports used by WeVote developers in their local setups

| Server | Served by | port | purpose |
|--------------------------------------------------|:-----------------------------:|-----:|:---------------------------|
| "WebApp" React webapp for voters | webpack serve/express | 3000 | Client App -- Voter facing |
| WeVoteServer (Python) API Server for "WebApp" | django runserver/runsslserver | 8000 | API Server -- Python |
| weconnect React webapp for staff | webpack serve/express | 4000 | Client App -- Staff facing |
| weconnect-server (Node) API server for weconnect | express | 4500 | API Server -- Node |
| postgres local server | postgres | 5432 | Database Server |

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"react-truncate-markup": "~5.1.0",
"rxjs": "^6.6.7",
"styled-components": "~5.3.11",
"topojson-client": "^3.1.0"
"topojson-client": "^3.1.0",
"validator": "^13.12.0"
},
"eslintConfig": {
"extends": [
Expand Down
2 changes: 1 addition & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const webAppConfig = require("./src/js/config");
module.exports = function (PROD) {
const port = 4000; // PROD ? 3000 : 3003;
const opts = { redirect: true };
const hostname = PROD ? webAppConfig.WE_VOTE_HOSTNAME : "localhost";
const hostname = PROD ? webAppConfig.HOSTNAME : "localhost";
const secureCertificateInstalled = webAppConfig.SECURE_CERTIFICATE_INSTALLED || false;

app.use("/", express.static("build", opts));
Expand Down
5 changes: 3 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import ReactGA from 'react-ga4';
import TagManager from 'react-gtm-module';
import { Route, Switch, withRouter } from 'react-router-dom';
import styled from 'styled-components';
import VoterActions from './js/actions/VoterActions';
import VoterSessionActions from './js/actions/VoterSessionActions';
import muiTheme from './js/common/components/Style/muiTheme';
import LoadingWheelComp from './js/common/components/Widgets/LoadingWheelComp';
Expand All @@ -15,11 +14,12 @@ import { getAndroidSize, getIOSSizeString, hasDynamicIsland, isIOS } from './js/
import historyPush from './js/common/utils/historyPush';
import { normalizedHref } from './js/common/utils/hrefUtils';
import initializejQuery from './js/common/utils/initializejQuery';
import { isAndroid, isCordova, isWebApp } from './js/common/utils/isCordovaOrWebApp';
import { isCordova, isWebApp } from './js/common/utils/isCordovaOrWebApp';
import { renderLog } from './js/common/utils/logging';
import HeaderBarSuspense from './js/components/Navigation/HeaderBarSuspense';
import webAppConfig from './js/config';
import VoterStore from './js/stores/VoterStore';
import Login from './js/pages/Login';
// importRemoveCordovaListenersToken1 -- Do not remove this line!

// Root URL pages
Expand Down Expand Up @@ -274,6 +274,7 @@ class App extends Component {
<Suspense fallback={<LoadingWheelComp />}>
<Switch>
<Route path="/faq" exact><FAQ /></Route>
<Route path="/login" exact><Login /></Route>
<Route path="/team-members/:teamId" exact component={TeamMembers} />

<Route path="*" component={PageNotFound} />
Expand Down
24 changes: 13 additions & 11 deletions src/js/config-template.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
/* eslint-disable */
// Note that we import these values where needed as "webAppConfig"
module.exports = {
WECONNECT_NAME_FOR_BROWSER_TAB_TITLE: 'WeConnect',
WECONNECT_URL_PROTOCOL: 'http://', // 'http://' for local dev (if not using SSL), or 'https://' for live server
WECONNECT_HOSTNAME: 'localhost:4000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:4000'
WECONNECT_IMAGE_PATH_FOR_CORDOVA: 'https://wevote.us', // If you are not working with Cordova, you don't need to change this
// weconnect React server for the "weconnect" web app
NAME_FOR_BROWSER_TAB_TITLE: 'WeConnect',
PROTOCOL: 'http://', // 'http://' for local dev (if not using SSL), or 'https://' for live server
HOSTNAME: 'localhost:4000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:4000'
PORT: 'localhost:4000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:4000'
IMAGE_PATH_FOR_CORDOVA: 'https://wevote.us', // If you are not working with Cordova, you don't need to change this
SECURE_CERTIFICATE_INSTALLED: false,

///////////////////////////////////////////////
// Keep both configuration blocks below, but only uncomment one of them at a time.
//// Connecting to local WeConnect APIs ////
WECONNECT_SERVER_ROOT_URL: 'http://localhost:8080/',
WECONNECT_SERVER_ADMIN_ROOT_URL: 'http://localhost:8080/admin/',
WECONNECT_SERVER_API_ROOT_URL: 'http://localhost:8080/apis/v1/',
WECONNECT_SERVER_API_CDN_ROOT_URL: 'http://localhost:8080/apis/v1/',
//// Connecting to local WeConnect "weconnect-server" APIs ////
WECONNECT_SERVER_ROOT_URL: 'http://localhost:4500/',
WECONNECT_SERVER_ADMIN_ROOT_URL: 'http://localhost:4500/admin/',
WECONNECT_SERVER_API_ROOT_URL: 'http://localhost:4500/apis/v1/',
WECONNECT_SERVER_API_CDN_ROOT_URL: 'http://localhost:4500/apis/v1/',
//// Connecting to live WeConnect APIs ////
// WECONNECT_SERVER_ROOT_URL: 'https://weconnectserver.org/',
// WECONNECT_SERVER_ADMIN_ROOT_URL: 'https://weconnectserver.org/admin/',
// WECONNECT_SERVER_API_ROOT_URL: 'https://weconnectserver.org/apis/v1/',
// WECONNECT_SERVER_API_CDN_ROOT_URL: 'https://cdn.weconnectserver.org/apis/v1/',

// For when we need to connect to the WeVoteServer APIs
// For when we need to connect to the WeVoteServer (Python) APIs
WE_VOTE_URL_PROTOCOL: 'http://', // 'http://' for local dev (if not using SSL), or 'https://' for live server
WE_VOTE_HOSTNAME: 'localhost:3000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:3000'
WE_VOTE_HOSTNAME: 'localhost:8000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:3000'

///////////////////////////////////////////////
// Keep both configuration blocks below, but only uncomment one of them at a time.
Expand Down
210 changes: 210 additions & 0 deletions src/js/pages/Login.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { Button, TextField } from '@mui/material';
import React, { useRef } from 'react';
import { Helmet } from 'react-helmet-async';
import PropTypes from 'prop-types';
import validator from 'validator';
import { withStyles } from '@mui/styles';
import styled from 'styled-components';
import { PageContentContainer } from '../components/Style/pageLayoutStyles';
import webAppConfig from '../config';
import { renderLog } from '../common/utils/logging';

/* global $ */

const Login = ({ classes }) => {
const nameFldRef = useRef('');
const locationFldRef = useRef('');
const emailFldRef = useRef('');
const email2FldRef = useRef('');
const passwordFldRef = useRef('');
const confirmPasswordFldRef = useRef('');
const [showCreateStuff, setShowCreateStuff] = React.useState(false);
const [warningLine, setWarningLine] = React.useState('');
const [successLine, setSuccessLine] = React.useState('');

renderLog('Login'); // Set LOG_RENDER_EVENTS to log all renders

const loginApi = (email, password) => {
console.log(`${webAppConfig.WECONNECT_SERVER_API_ROOT_URL}login`);
$.post(`${webAppConfig.WECONNECT_SERVER_API_ROOT_URL}login/`,
{ email, password },
(data, status) => {
console.log(`/login response -- status: '${status}', data: ${JSON.stringify(data)}`);
if (data.userId > 0) {
setWarningLine('');
setSuccessLine(`Cheers! &nbsp;You are signed in! &nbsp;Person #${data.userId}.`);
} else {
setWarningLine(data.errors.msg);
setSuccessLine('');
}
});
};

const signupApi = (name, location, email, email2, password, confirmPassword) => {
$.post(`${webAppConfig.WECONNECT_SERVER_API_ROOT_URL}signup`,
{ name, location, email, email2, password, confirmPassword },
(data, status) => {
console.log(`/signup response -- status: '${status}', data: ${JSON.stringify(data)}`);
let errStr = '';
for (let i = 0; i < data.errors.length; i++) {
errStr += data.errors[i].msg;
}
setWarningLine(errStr);
if (data.personCreated) {
setSuccessLine(`user # ${data.userId} created, and signedIn is ${data.signedIn}`);
}
});
};

const loginPressed = () => {
const email = emailFldRef.current.value;
const password = passwordFldRef.current.value;

if (email.length === 0 || password.length === 0) {
console.log('too short');
setWarningLine('Enter a valid username and password');
} else {
setWarningLine('');
loginApi(email, password);
}
};

const createPressed = () => {
if (!showCreateStuff) {
setShowCreateStuff(true);
setWarningLine('');
setSuccessLine('');
} else {
setWarningLine('');
let errStr = '';
const name = nameFldRef.current.value;
const location = locationFldRef.current.value;
const email = emailFldRef.current.value;
const email2 = email2FldRef.current.value;
const password = passwordFldRef.current.value;
const confirmPassword = confirmPasswordFldRef.current.value;
if (!validator.isEmail(email)) errStr += 'Please enter a valid primary email address.';
if (!validator.isEmail(email2)) errStr += 'Please enter a valid secondary email address.';
if (!validator.isLength(password, { min: 8 })) errStr += 'Password must be at least 8 characters long';
if (validator.escape(password) !== validator.escape(confirmPassword)) errStr += 'Passwords do not match';

if (errStr.length) {
setWarningLine(errStr);
} else {
signupApi(name, location, email, email2, password, confirmPassword);
}
}
};

return (
<div>
<Helmet>
<title>
Login -
{' '}
{webAppConfig.NAME_FOR_BROWSER_TAB_TITLE}
</title>
</Helmet>
<PageContentContainer>
<h1>
Sign in
</h1>

<div id="warningLine" style={{ color: 'red', paddingTop: '10px', paddingBottom: '20px' }}>{warningLine}</div>
<div id="successLine" style={{ color: 'green', paddingTop: '10px', paddingBottom: '20px' }}>{successLine}</div>
<TextField id="outlined-basic"
label="Name"
variant="outlined"
inputRef={nameFldRef}
sx={{ paddingBottom: '15px',
display: showCreateStuff ? 'block' : 'none' }}
/>
<TextField id="outlined-basic"
label="Location"
variant="outlined"
inputRef={locationFldRef}
helperText="City, State (2 chars)"
sx={{ paddingBottom: '15px',
display: showCreateStuff ? 'block' : 'none' }}
/>
<TextField id="outlined-basic"
label="Email"
helperText={showCreateStuff ? 'Required, possibly your personal email' : ''}
variant="outlined"
inputRef={emailFldRef}
sx={{ display: 'block', paddingBottom: '15px' }}
/>
<TextField id="outlined-basic"
label="Second Email"
helperText="Optional, possibly your wevote.us email"
variant="outlined"
inputRef={email2FldRef}
sx={{ paddingBottom: '15px',
display: showCreateStuff ? 'block' : 'none' }}
/>
<TextField id="outlined-basic"
label="Password"
variant="outlined"
inputRef={passwordFldRef}
sx={{ display: 'block', paddingBottom: '15px' }}
/>
<TextField id="outlined-basic"
label="Confirm Password"
variant="outlined"
inputRef={confirmPasswordFldRef}
sx={{ paddingBottom: '15px', display: showCreateStuff ? 'block' : 'none' }}
/>
<span style={{ display: 'flex' }}>
<Button
classes={{ root: classes.loginButtonRoot }}
color="primary"
variant="contained"
onClick={showCreateStuff ? createPressed : loginPressed}
sx={{ paddingBottom: '15px', display: showCreateStuff ? 'none' : 'flex' }}
>
Sign In
</Button>
<A style={{ display: showCreateStuff ? 'none' : 'flex' }}>Forgot your password?</A>
</span>
<div style={{ paddingTop: '35px' }} />
<Button
classes={{ root: classes.buttonDesktop }}
color="primary"
variant="contained"
onClick={createPressed}
>
{showCreateStuff ? 'Save New Account' : 'Create Account'}
</Button>

<div style={{ paddingTop: '80px' }}>
This page&apos;s purpose is to test and exercise the API. Feel free to replace me.
</div>
</PageContentContainer>
</div>
);
};
Login.propTypes = {
classes: PropTypes.object.isRequired,
};

const styles = (theme) => ({
ballotButtonIconRoot: {
marginRight: 8,
},
loginButtonRoot: {
width: 100,
[theme.breakpoints.down('md')]: {
width: '100%',
},
},
});

const A = styled('a')`
font-weight: 400;
color: rgb(13, 110, 253);
text-decoration-color: rgb(13, 110, 253);
text-decoration-line: underline;
padding: 8px 0 0 25px;
`;

export default withStyles(styles)(Login);
2 changes: 1 addition & 1 deletion src/js/pages/TeamMembers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const TeamMembers = ({ classes, match }) => { // classes, teamId
<title>
Team Members -
{' '}
{webAppConfig.WECONNECT_NAME_FOR_BROWSER_TAB_TITLE}
{webAppConfig.NAME_FOR_BROWSER_TAB_TITLE}
</title>
<link rel="canonical" href={`${webAppConfig.WECONNECT_URL_FOR_SEO}/team-members`} />
</Helmet>
Expand Down

0 comments on commit 7cdaf19

Please sign in to comment.