diff --git a/.eslintrc b/.eslintrc index 11936e2..3d4feaf 100644 --- a/.eslintrc +++ b/.eslintrc @@ -56,6 +56,7 @@ "react/destructuring-assignment": 0, // Dec 2018: We should do this! But right now we have 3990 warnings/errors if enabled. "react/forbid-prop-types": 0, // Dec 2018: Should consider someday "react/indent-prop": 0, + "react/jsx-curly-newline": 0, // Feb 2025, started showing up with latest eslint "react/jsx-first-prop-new-line": 0, "react/jsx-indent-props": 0, "react/jsx-no-bind": 1, // Dec 2018: Should these be errors? diff --git a/README.md b/README.md index ee1962d..40f62a9 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,309 @@ -# WeConnect +# WeConnect Client -This WeConnect repository contains a Node/React/Flux Javascript application. +This WeConnect Client repository (weconnect-client) contains a React Javascript application, that is used to manage WeVote +volunteer teams. + +Alt Text Interested in [volunteering or applying for an internship](https://wevote.applytojob.com/apply)? [Starting presentation here](https://prezi.com/p/6iu9aks7zqvs/?present=1). Please also [read about our values](https://docs.google.com/document/d/12qBXevI3mVKUsGmXL8mrDMPnWJ1SYw9zX9LGW5cozgg/edit) and -[see our Code of Conduct](CODE_OF_CONDUCT.md) +[see our Code of Conduct](https://github.com/wevote/WebApp/blob/435304bc1edd7a8d4d0abdae8c46a533a0ecf52c/CODE_OF_CONDUCT.md) To join us, please [review our openings here](https://wevote.applytojob.com/apply), and apply for a volunteer position through that page. -Our current version is here [https://WeVote.US](https://WeVote.US) and we are working on a new version now! +The current version of our flagship voter app is here [https://WeVote.US](https://WeVote.US), and we are working on a new version now! -## Installing WeConnect - WORK IN PROGRESS Our installation process is built to allow engineers all over America to contribute. It may seem complicated, but it allows anyone to be in a position to make suggestions, and get involved. -Installation on MacOs and Linux -1. [Preparing the Environment on Your Machine (MacOS and Linux)](docs/installing/ENVIRONMENT.md) +## Installing the React weconnect-client + +These instruction assume that you are installing on a Mac. If you use Windows or Linux, the installation procedure should be similar. + +This procedure is based on using the free Community edition of WebStorm, which has great Git integration, +a great integrated Node debugger, and has an excellent editor. + +If you have the paid version of WebStorm the instructions should be the same. + +**If you have some other preferred editor, we recommend that you still do this install, and then use your other editor as you wish!** +

+ +### If you don't already have one, create an account in [GitHub](https://github.com/) +[GitHub](https://github.com/) is where WeVote stores the source code for our various projects. +

+ +### Download and install WebStorm +The free Community edition is at https://www.jetbrains.com/webstorm/ + +License it as a free Community installation. + +Once installed, start WebStorm from Launch Pad or Spotlight + +Alt Text + +The first step is to press that "Clone Repository" button to clone the https://github.com/wevote/weconnect-client repository. +Enter the URL and press the Clone button. + +Alt Text + +Now the latest code is on your machine. + +Alt Text +

+ +### Configure the WebStorm display mode +If you like the default white characters on a black background, skip this step. + +Access the settings dialog from the gear icon in the upper right hand side of the WebStorm app. +Set the Theme as you would like, or have it "Sync with OS" (which is my preference), and then save. +

+ +Alt Text +

+ +### About WebStorm plugins +Plugins extend the capability of WebStorm and are worth exploring. If it sounds good, we usually install them, unless the suggestions are for off-topic for what we are useing WebStorm for today. +Plugins suggested by WebStorm are safe to install, and easy to remove if you don't like them. +

+ +### Run 'npm install' +If WebStorm prompts you to run "npm install" feel free to do it anytime. + +Alt Text + +"npm install" updates all the dependencies (node_modules i.e. libraries) that we import from other projects, and should never be a problem. + +"npm install" will often show lots of outdated libraries, and vulnerabilities ... WeVote gets +reports on these issues, and we resolve them periodically. Don't worry about the warnings at this point. + + + +### Install Homebrew (If it is not already installed) +If you are reading this file in WebStorm, click the green double arrow to the left of the following command, +to install [Homebrew](https://brew.sh/). Otherwise, open a terminal window at the bottom of Webstorm, and +paste the following command into the terminal and run it. + +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` +The following output will appear in the terminal window. You will need your login password to allow macOS +to install Homebrew. When it prompts you for an "ENTER" you can click in the terminal, and press Enter. + +``` +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +stevepodell@Steves-MBP-M1-Dec2021 weconnect-client % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +==> Checking for `sudo` access (which may request your password)... +Password: +==> This script will install: +/opt/homebrew/bin/brew +/opt/homebrew/share/doc/homebrew +/opt/homebrew/share/man/man1/brew.1 +/opt/homebrew/share/zsh/site-functions/_brew +/opt/homebrew/etc/bash_completion.d/brew +/opt/homebrew + +Press RETURN/ENTER to continue or any other key to abort: +``` +Homebrew will load many many "formulae" (their cutesy name for scripts that install all sorts of +free open source programs). If you already had Homebrew installed, it will update +any ("taps" which are "formulae" that were already installed). + +When Homebrew completes it will leave the terminal window at a macOS (Linux) prompt. + +You will now use Homebrew to install some more applications. +

+ +### Install Node +This project has a few scripts that run in Node, get the latest version of at least 22.0
+If you have an earlier version of Node installed, you will need to reinstall it. + +Check your node version via the terminal (This computer was at V18, and needed to be upgraded. Node had been previously installed with +Homebrew. "homebrew" is in the path to the Node executable (`/opt/homebrew/bin/node`), so we know it was installed with Homebrew.) + +``` +stevepodell@Steves-MacBook-Air weconnect-client % which node +/opt/homebrew/bin/node +stevepodell@Steves-MacBook-Air weconnect-client % node -v +v18.10.0 +stevepodell@Steves-MacBook-Air weconnect-client % +``` + +If your computer did not have Node installed with Homebrew, you will have to research how to upgrade your installation of Node. + +If Node was installed with Homebrew or you have never installed Node, continue... + +```bash + stevepodell@Steves-MacBook-Air weconnect-client % brew install node@22 + ... + ==> Caveats + node@22 is keg-only, which means it was not symlinked into /usr/local, + because this is an alternate version of another formula. + + If you need to have node@22 first in your PATH, run: + echo 'export PATH="/usr/local/opt/node@22/bin:$PATH"' >> ~/.zshrc + + For compilers to find node@22 you may need to set: + export LDFLAGS="-L/usr/local/opt/node@22/lib" + export CPPFLAGS="-I/usr/local/opt/node@22/include" + ==> Summary +🍺 /usr/local/Cellar/node@22/22.11.0: 2,628 files, 83.7MB + ==> Running `brew cleanup node@22`... + Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP. + Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`). + stevepodell@Steves-MacBook-Air weconnect-client % +``` +If Homebrew asks you to make the following 4 manual changes to link in Node. Execute these 4 lines in your terminal. +```bash +stevepodell@Steves-MacBook-Air weconnect-client % echo 'export PATH="/usr/local/opt/node@22/bin:$PATH"' >> ~/.zshrc +stevepodell@Steves-MacBook-Air weconnect-client % echo 'export PATH="/usr/local/opt/node@22/bin:$P +stevepodell@Steves-MacBook-Air weconnect-client % export LDFLAGS="-L/usr/local/opt/node@22/lib" +stevepodell@Steves-MacBook-Air weconnect-client % export CPPFLAGS="-I/usr/local/opt/node@22/include" +stevepodell@Steves-MacBook-Air weconnect-client % +``` +Then confirm the version of Node is greater than V22, open a new terminal window (with the "+" icon) and type + +``` +stevepodell@Steves-MacBook-Air weconnect-client % node -v +v22.11.0 +stevepodell@Steves-MacBook-Air weconnect-client % +``` +

+ +### Set up your Git remotes within WebStorm + +Alt Text + +At WeVote we use different naming conventions for `origin` and `upstream` than you might be familiar with from other projects, so you +will need to rename the default git origin (which at WeVote is your private branch in GitHub +) + +Alt Text + +Edit the origin line, and change the name to upstream, then press OK + +Alt Text + +Then press the + button and set up the new value for “origin”. +(DON’T USE SailingSteve — use your GitHub handle — the GitHub username that is in the URL after you sign in to GitHub .) + +Alt Text + +You may have to authenticate with GitHub at this point. After completing the GitHub authentication, continue... + +When done, your remotes will look something like this (with your GitHub handle instead of SailingSteve!) + +Alt Text + +At this point you are poised to make Git branches and pull requests. +

+ +### Load all the Node packages that we use in the weconnect-client +If you haven't already done this via a prompt from Webstorm, type +``` +stevepodell@Steves-MacBook-Air weconnect-client % npm install +``` +You can run this command as often as you want, and it will cause no harm. +

+ +### Make a live copy of config-template.js to the config.js file + +Right-click on the `config-template.js` file in Webstorm, and copy it, then paste it as `config.js` + +Alt Text +Alt Text + +If WebStorm did not automatically open `config.js` in a tab, then double click it in the Project pane to open it +for editing. + +Alt Text + +### Setup the connection to a weconnect-server (API server) + +**Option 1:** Use the weconnect-server running in Amazon AWS + + Note: As of March 5, 2025 the weconnect-server is not yet running in Amazon AWS cloud, so this option is not available. + +This is all you need if initially you will not be developing new API endpoints, and you won't initially need to debug +aPI server side code. + +Uncomment these four STAFF_API_SERVER_ lines, and make sure the other two sets of lines like this are commented out. + +``` + //// Connecting to live WeConnect APIs //// + // STAFF_API_SERVER_ROOT_URL: 'https://weconnectserver.org/', + // STAFF_API_SERVER_ADMIN_ROOT_URL: 'https://weconnectserver.org/admin/', + // STAFF_API_SERVER_API_ROOT_URL: 'https://weconnectserver.org/apis/v1/', + // STAFF_API_SERVER_API_CDN_ROOT_URL: 'https://cdn.weconnectserver.org/apis/v1/', +``` + + +**Option 2:** Run a weconnect-server instance on your computer using https SSL/TLS + +In this case you will have already setup the [weconnect-server](https://github.com/wevote/weconnect-server) and postgres on your computer and have it running. + +For this option you will need to get the wevotedeveloper.com certificates from Dale. + +Uncomment these four STAFF_API_SERVER_ lines, and make sure the other two sets of lines like this are commented out. + +``` + //// weconnect-server local server running SSL/TLS HTTPS + // STAFF_API_SERVER_ROOT_URL: 'https://wevotedeveloper.com:4500/', + // STAFF_API_SERVER_ADMIN_ROOT_URL: 'https://wevotedeveloper.com:4500/admin/', + // STAFF_API_SERVER_API_ROOT_URL: 'https://wevotedeveloper.com:4500/apis/v1/', + // STAFF_API_SERVER_API_CDN_ROOT_URL: 'https://wevotedeveloper.com:4500/apis/v1/', +``` + + +**Option 3:** (Not recommended) Run a non-secure weconnect-server instance on your computer using http + +This may work for some limited purposes, but your session may not be maintained as you navigate to the React app in +different tabs on your browser, and you may have authentication problems, or API query response problems. + +Uncomment these four STAFF_API_SERVER_ lines, and make sure the other two sets of lines like this are commented out. +``` + //// Connecting to local WeConnect "weconnect-server" APIs //// + // STAFF_API_SERVER_ROOT_URL: 'http://localhost:4500/', + // STAFF_API_SERVER_ADMIN_ROOT_URL: 'http://localhost:4500/admin/', + // STAFF_API_SERVER_API_ROOT_URL: 'http://localhost:4500/apis/v1/', + // STAFF_API_SERVER_API_CDN_ROOT_URL: 'http://localhost:4500/apis/v1/', +``` + +Not in this project, but in the **weconnect-server project** on your computer, change the PROTOCOL line in the .env file from +`PROTOCOL=https://` to `PROTOCOL=http://` and restart the weconnect-server, and then it will come up in http mode. + +### Add a Run Configuration in WebStorm to start the weconnect-client + +Open the pull-down that initially says "Current File", and select Edit Configurations +
+Alt Text
+ +In the Run/Debug Configurations dialog, press the "+" button and then select "Node.js" +Alt Text
+Then fill in the run configuration... +1) Enter `Start weconnect-client` in the Scripts field. +2) And press "OK" to save +
Alt Text +

+ +### Start the app! +First start postgres via the run configuration + +As you can see when you press the Green start arrow, the server starts up in a terminal window where you can see +some logging from the Webpack server program. The `run start` starts up the Webpack server, which listens for any changes to the files in your IDE and then +automatically 'recompiles' and 'redeploys' the changes to your browser. + +Webpack takes a minute or two to start up, but then it recompiles in less that a second. As you make changes in your code +you will see the line that says something like `webpack 5.97.1 compiled successfully in 795 ms` change for each compile. +Webpack will eventually see the changes to you code when Webstorm automatically saves the file, but you can get those +recompiles to happen instantly by either pressing the save floppy-disk icon on the top row, or by pressing Command+S + +In your browser you can press Control+Shift+R to reload the page with the latest from Webpack (although this also will +happen automatically after a few seconds). Control+Shift+R guranatees a full reload, which sometimes does not happen +if modal dialogs or drawers are open. + +Debugging of the code is done with Chrome Dev-tools, which can be invoked by right-clicking anywhere on the page, and +selecting 'Inspect' at the bottom of the right-click menu. + +### View the app in the Chrome browser + +When you navigate in Chrome to `http://localhost:4000/` you will see the client login page. + diff --git a/docs/images/AppScreenShot.png b/docs/images/AppScreenShot.png new file mode 100644 index 0000000..509ee1a Binary files /dev/null and b/docs/images/AppScreenShot.png differ diff --git a/docs/images/CodeInstalledInWebStorm.png b/docs/images/CodeInstalledInWebStorm.png new file mode 100644 index 0000000..dd19f5f Binary files /dev/null and b/docs/images/CodeInstalledInWebStorm.png differ diff --git a/docs/images/GitOriginMine.png b/docs/images/GitOriginMine.png new file mode 100644 index 0000000..2010c2b Binary files /dev/null and b/docs/images/GitOriginMine.png differ diff --git a/docs/images/GitRemoteOriginBefore.png b/docs/images/GitRemoteOriginBefore.png new file mode 100644 index 0000000..3b41427 Binary files /dev/null and b/docs/images/GitRemoteOriginBefore.png differ diff --git a/docs/images/GitRemoteUpstreamAfter.png b/docs/images/GitRemoteUpstreamAfter.png new file mode 100644 index 0000000..f891cce Binary files /dev/null and b/docs/images/GitRemoteUpstreamAfter.png differ diff --git a/docs/images/GitRemotesDone.png b/docs/images/GitRemotesDone.png new file mode 100644 index 0000000..61f3042 Binary files /dev/null and b/docs/images/GitRemotesDone.png differ diff --git a/docs/images/ManageRemotesMenu.png b/docs/images/ManageRemotesMenu.png new file mode 100644 index 0000000..3d4254b Binary files /dev/null and b/docs/images/ManageRemotesMenu.png differ diff --git a/docs/images/NpmConfigFilledIn.png b/docs/images/NpmConfigFilledIn.png new file mode 100644 index 0000000..701f4f3 Binary files /dev/null and b/docs/images/NpmConfigFilledIn.png differ diff --git a/docs/images/NpmInstall.png b/docs/images/NpmInstall.png new file mode 100644 index 0000000..dc26a5e Binary files /dev/null and b/docs/images/NpmInstall.png differ diff --git a/docs/images/RunConfigMenu.png b/docs/images/RunConfigMenu.png new file mode 100644 index 0000000..2fea02b Binary files /dev/null and b/docs/images/RunConfigMenu.png differ diff --git a/docs/images/RunInHTTP.png b/docs/images/RunInHTTP.png new file mode 100644 index 0000000..133916c Binary files /dev/null and b/docs/images/RunInHTTP.png differ diff --git a/docs/images/SelectNpmFromList.png b/docs/images/SelectNpmFromList.png new file mode 100644 index 0000000..fd8ade7 Binary files /dev/null and b/docs/images/SelectNpmFromList.png differ diff --git a/docs/images/WebStormAppearanceSettings.png b/docs/images/WebStormAppearanceSettings.png new file mode 100644 index 0000000..2ab4f9e Binary files /dev/null and b/docs/images/WebStormAppearanceSettings.png differ diff --git a/docs/images/WebstormCloneRepository.png b/docs/images/WebstormCloneRepository.png new file mode 100644 index 0000000..c5022d7 Binary files /dev/null and b/docs/images/WebstormCloneRepository.png differ diff --git a/docs/images/WebstormCopySelection.png b/docs/images/WebstormCopySelection.png new file mode 100644 index 0000000..d080d57 Binary files /dev/null and b/docs/images/WebstormCopySelection.png differ diff --git a/docs/images/WebstormEditConfig.png b/docs/images/WebstormEditConfig.png new file mode 100644 index 0000000..6cf18e5 Binary files /dev/null and b/docs/images/WebstormEditConfig.png differ diff --git a/docs/images/WebstormPaste.png b/docs/images/WebstormPaste.png new file mode 100644 index 0000000..7f5a003 Binary files /dev/null and b/docs/images/WebstormPaste.png differ diff --git a/docs/images/WelcomeToWebStorm.png b/docs/images/WelcomeToWebStorm.png new file mode 100644 index 0000000..36c9b76 Binary files /dev/null and b/docs/images/WelcomeToWebStorm.png differ diff --git a/src/js/common/utils/logging.js b/src/js/common/utils/logging.js index 31dc669..14cdad3 100644 --- a/src/js/common/utils/logging.js +++ b/src/js/common/utils/logging.js @@ -43,7 +43,7 @@ export function httpLog (text, res) { } } -// Log oAuth steps +// Log auth steps export function authLog (text, res) { if (webAppConfig.LOG_AUTHENTICATION) { if (res) { diff --git a/src/js/components/Login/ResetYourPassword.jsx b/src/js/components/Login/ResetYourPassword.jsx index 5f52dfd..79aa3c2 100644 --- a/src/js/components/Login/ResetYourPassword.jsx +++ b/src/js/components/Login/ResetYourPassword.jsx @@ -8,11 +8,11 @@ import TextField from '@mui/material/TextField'; import PropTypes from 'prop-types'; import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; +import styled from 'styled-components'; import validator from 'validator'; import { renderLog } from '../../common/utils/logging'; import { useConnectAppContext } from '../../contexts/ConnectAppContext'; -import makeRequestParams from '../../react-query/makeRequestParams'; -import { useLogoutMutation, usePersonRetrieveByEmailMutation, usePersonSaveForAuthMutation } from '../../react-query/mutations'; +import { useLogoutMutation, usePasswordSaveMutation, usePersonRetrieveByEmailMutation } from '../../react-query/mutations'; import weConnectQueryFn, { METHOD } from '../../react-query/WeConnectQuery'; import { ErrorMessage } from '../Style/sharedStyles'; import VerifySecretCodeModal from '../VerifySecretCodeModal'; @@ -20,19 +20,22 @@ import VerifySecretCodeModal from '../VerifySecretCodeModal'; const ResetYourPassword = ({ openDialog, closeDialog }) => { renderLog('ResetYourPassword'); const { mutate: mutateRetrievePersonByEmail } = usePersonRetrieveByEmailMutation(); - const { mutate: mutatePersonSaveForAuth } = usePersonSaveForAuthMutation(); + const { mutate: mutatePasswordSave } = usePasswordSaveMutation(); const { mutate: mutateLogout } = useLogoutMutation(); const { getAppContextValue, setAppContextValue } = useConnectAppContext(); + // console.log('ResetYourPassword ', getAppContextData()); const [open, setOpen] = React.useState(openDialog); const [displayEmailAddress, setDisplayEmailAddress] = useState(true); const [warningLine, setWarningLine] = useState(''); const [errorMessage, setErrorMessage] = useState(''); + const [personId, setPersonId] = useState(''); const emailRef = useRef(''); + const emailDisabledRef = useRef(''); const password1Ref = useRef(''); const password2Ref = useRef(''); - const authPerson = useRef(undefined); + const authPersonRef = useRef(undefined); useEffect(() => { setOpen(openDialog); @@ -43,6 +46,7 @@ const ResetYourPassword = ({ openDialog, closeDialog }) => { if (secretCodeVerified === true) { console.log('received new secretCodeVerifiedForReset', secretCodeVerified); setDisplayEmailAddress(false); + emailDisabledRef.current = authPersonRef.current?.emailPersonal || ''; emailRef.current = ''; password1Ref.current = ''; password2Ref.current = ''; @@ -52,11 +56,9 @@ const ResetYourPassword = ({ openDialog, closeDialog }) => { const auth = getAppContextValue('authenticatedPerson'); useEffect(() => { const authP = getAppContextValue('authenticatedPerson'); + authPersonRef.current = authP; if (authP && open) { - console.log('received new authP', authP); - authPerson.current = authP; - console.log('authPerson.personId in Login useEffect [auth] id: ', authP.personId); - console.log('authPerson.personId in Login useEffect [auth] open: ', open); + setPersonId(authP.personId); weConnectQueryFn('send-email-code', { personId: authP.personId }, METHOD.POST) .then(setAppContextValue('openVerifySecretCodeModalDialog', true)); } @@ -64,21 +66,6 @@ const ResetYourPassword = ({ openDialog, closeDialog }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [auth]); - const sendEmail = async () => { - const email = emailRef.current.value; - setAppContextValue('resetEmail', email); - console.log('email in sendEmail: ', emailRef.current.value); - if (!validator.isEmail(email)) { - setWarningLine('Please enter a valid email address.'); - return; - } - setWarningLine(''); - setAppContextValue('openVerifySecretCodeModalDialog', true); - // Logout so that the current sessionID will not be reused when resetting password for a potentially differnt staff member - await mutateLogout(); - // This retrieve will set the 'authenticatedPerson' app context value, and bring back a new sessionID (without touching the cookie) - await mutateRetrievePersonByEmail({ emailPersonal: email }); - }; const handleClose = () => { setOpen(false); @@ -88,23 +75,41 @@ const ResetYourPassword = ({ openDialog, closeDialog }) => { const changePassword = async () => { const pass1 = password1Ref.current.value; const pass2 = password2Ref.current.value; - const person = authPerson.current; + const person = authPersonRef.current; + let id; + if (person?.id) { + id = person.id; + } else { + id = personId; + } - console.log('password in changePassword: ', pass1, pass2); if (pass1 !== pass2) { setErrorMessage('Your password entries do not match.'); } else { setErrorMessage(''); - // const person = getAppContextValue('authenticatedPerson'); - await mutatePersonSaveForAuth(makeRequestParams({ id: person.id }, { password: pass1 })); + await mutatePasswordSave({ personId: id, password: pass1 }); setAppContextValue('isAuthenticated', true); - console.log('ResetYourPassword changePassword pass1, pass2: ', pass1, pass2); + setAppContextValue('authenticatedPerson', person); setAppContextValue('resetPassword', pass1); handleClose(); } }; - console.log('ResetYourPassword incoming authPerson: ', authPerson); + const sendEmail = async () => { + const email = emailRef.current.value; + setAppContextValue('resetEmail', email); + if (!validator.isEmail(email)) { + setWarningLine('Please enter a valid email address.'); + return; + } + setWarningLine(''); + setAppContextValue('openVerifySecretCodeModalDialog', true); + // Logout so that the current sessionID will not be reused when resetting password for a potentially differnt staff member + await mutateLogout(); + // This retrieve will set the 'authenticatedPerson' app context value, and bring back a new sessionID (without touching the cookie) + await mutateRetrievePersonByEmail({ emailPersonal: email }); + }; + return ( <> { name="email" required type="email" - variant="standard" + variant="outlined" /> ) : ( -
+ <> + {/* EmailDiv clues in Google "Update password?" dialog to display this email, it probably could be css hidden */} + Email:    {emailDisabledRef.current} - + )}
- + {!isAuthSafe && ( + + )} + {isAdmin && ( + + )}
- {authPerson.current && - Object.keys(authPerson.current).length > 0 && - getAppContextValue('secretCodeVerified') !== true && - getAppContextValue('openVerifySecretCodeModalDialog') && ( - - )} - - {/* This following test can be deleted or converted to an automated test */} - {/* */} + {displayVerify && } +
); diff --git a/src/js/pages/SystemSettings/PermissionsAdministration.jsx b/src/js/pages/SystemSettings/PermissionsAdministration.jsx index 60fa972..276fd5a 100644 --- a/src/js/pages/SystemSettings/PermissionsAdministration.jsx +++ b/src/js/pages/SystemSettings/PermissionsAdministration.jsx @@ -10,6 +10,7 @@ import { viewerCanSeeOrDo } from '../../models/AuthModel'; import { getFullNamePreferredPerson } from '../../models/PersonModel'; import makeRequestParams from '../../react-query/makeRequestParams'; import { usePersonSaveMutation } from '../../react-query/mutations'; +import { alphabetizePeoplesObject } from '../../utils/utilities'; /* global $ */ @@ -34,7 +35,8 @@ const PermissionsAdministration = ({ classes }) => { useEffect(() => { const allPeopleCacheCopy2 = JSON.parse(JSON.stringify(allPeopleCache)); - setPeopleWorkingArray(Object.values(allPeopleCacheCopy2)); + const sorted = alphabetizePeoplesObject(allPeopleCacheCopy2); + setPeopleWorkingArray(sorted); }, [allPeopleCache]); const adminFldRef = useRef(''); @@ -65,7 +67,7 @@ const PermissionsAdministration = ({ classes }) => { const cancelClicked = (event) => { const pieces = event.target.id.split('-'); const personId = parseInt(pieces[2]); - const activePerson = peopleWorkingArray.find((p) => p.id === personId); + const activePerson = peopleWorkingArray.find((p) => parseInt(p.id) === personId); const personCached = Object.values(allPeopleCache).find((p) => p.id === personId); Object.assign(activePerson, personCached); setButtonState(SET.DISABLE, personId); @@ -74,8 +76,8 @@ const PermissionsAdministration = ({ classes }) => { const saveClicked = (event) => { const personId = parseInt(event.target.id.split('-')[2]); - const activePerson = peopleWorkingArray.find((p) => p.id === personId); - const personCached = Object.values(allPeopleCache).find((p) => p.id === personId); + const activePerson = peopleWorkingArray.find((p) => parseInt(p.id) === personId); + const personCached = Object.values(allPeopleCache).find((p) => parseInt(p.id) === personId); const data = {}; Object.keys(activePerson).forEach((key) => { @@ -103,7 +105,7 @@ const PermissionsAdministration = ({ classes }) => { if (canEditPermissionsAnyone) { const pieces = event.target.id.split('-'); const personId = parseInt(pieces[2]); - const person = peopleWorkingArray.find((p) => p.id === personId); + const person = peopleWorkingArray.find((p) => parseInt(p.id) === personId); switch (pieces[1]) { case 'admin': person.isAdmin = event.target.checked; diff --git a/src/js/pages/Teams.jsx b/src/js/pages/Teams.jsx index 2f273dc..8b9e0c0 100644 --- a/src/js/pages/Teams.jsx +++ b/src/js/pages/Teams.jsx @@ -210,7 +210,7 @@ const Teams = () => { })}
- Sign in + Temporary link to /login page
diff --git a/src/js/react-query/mutations.jsx b/src/js/react-query/mutations.jsx index a8ac99b..4d5b644 100644 --- a/src/js/react-query/mutations.jsx +++ b/src/js/react-query/mutations.jsx @@ -1,4 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { reactQueryLog } from '../common/utils/logging'; import { useConnectAppContext } from '../contexts/ConnectAppContext'; import weConnectQueryFn, { METHOD } from './WeConnectQuery'; @@ -89,7 +90,7 @@ const usePersonAwaySaveMutation = () => { }); }; -// Moved to /models/PersonModel.jsx with a non-conflicting function name +// Copied to /models/PersonModel.jsx with a non-conflicting function name const usePersonSaveMutation = () => { const queryClient = useQueryClient(); @@ -100,16 +101,6 @@ const usePersonSaveMutation = () => { }); }; -const usePersonSaveForAuthMutation = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: (params) => weConnectQueryFn('person-save', params, METHOD.GET), - onError: (error) => console.log('error in personSaveMutation: ', error), - onSuccess: () => queryClient.invalidateQueries('get-auth'), - }); -}; - const useSaveTaskMutation = () => { const queryClient = useQueryClient(); @@ -134,33 +125,39 @@ const useGetAuthMutation = () => { return useMutation({ mutationFn: () => weConnectQueryFn('get-auth', {}, METHOD.POST), onError: (error) => console.log('error in useGetAuthMutation: ', error), - onSuccess: () => console.log('useGetAuthMutation called to force refresh'), + onSuccess: (auth) => reactQueryLog('useGetAuthMutation called to force refresh', auth), + }); +}; + +const usePasswordSaveMutation = () => { + return useMutation({ + mutationFn: (params) => weConnectQueryFn('save-password', params, METHOD.PUT), + onError: (error) => console.log('error in usePasswordSaveMutation: ', error), + onSuccess: (data, variables, context) => reactQueryLog('usePasswordSaveMutation successful, returning', data, variables, context), }); }; const usePersonRetrieveMutation = () => { - console.log('entry to useGetPersonMutation'); const { setAppContextValue } = useConnectAppContext(); return useMutation({ mutationFn: (params) => weConnectQueryFn('person-retrieve', params, METHOD.GET), onError: (error) => console.log('error in usePersonRetrieveMutation: ', error), onSuccess: (data, variables, context) => { - console.log('usePersonRetrieveMutation successful, returning', data, variables, context); + reactQueryLog('usePersonRetrieveMutation successful, returning', data, variables, context); setAppContextValue('authenticatedPerson', data); }, }); }; const usePersonRetrieveByEmailMutation = () => { - console.log('entry to useGetPersonMutation'); const { setAppContextValue } = useConnectAppContext(); return useMutation({ mutationFn: (params) => weConnectQueryFn('person-retrieve-by-email', params, METHOD.GET), onError: (error) => console.log('error in usePersonRetrieveByEmailMutation: ', error), onSuccess: (data, variables, context) => { - console.log('usePersonRetrieveByEmailMutation successful, returning', data, variables, context); + reactQueryLog('usePersonRetrieveByEmailMutation successful, returning', data, variables, context); setAppContextValue('authenticatedPerson', data); }, }); @@ -169,7 +166,7 @@ const usePersonRetrieveByEmailMutation = () => { export { useRemoveTeamMutation, useRemoveTeamMemberMutation, useAddPersonToTeamMutation, useQuestionnaireSaveMutation, useTaskDefinitionSaveMutation, useGroupSaveMutation, - usePersonAwaySaveMutation, - useQuestionSaveMutation, usePersonSaveMutation, usePersonSaveForAuthMutation, useSaveTaskMutation, useAnswerListSaveMutation, + usePersonAwaySaveMutation, usePasswordSaveMutation, + useQuestionSaveMutation, usePersonSaveMutation, useSaveTaskMutation, useAnswerListSaveMutation, useLogoutMutation, useGetAuthMutation, usePersonRetrieveMutation, usePersonRetrieveByEmailMutation }; diff --git a/src/js/utils/utilities.js b/src/js/utils/utilities.js new file mode 100644 index 0000000..1f6ac3c --- /dev/null +++ b/src/js/utils/utilities.js @@ -0,0 +1,7 @@ +// eslint-disable-next-line import/prefer-default-export +export const alphabetizePeoplesObject = (obj) => { + const arrayOfObjects = Object.keys(obj).map((key) => ({ ...obj[key], id: key })); + arrayOfObjects.sort((a, b) => (a.lastName + a.firstName).localeCompare(b.lastName + b.firstName)); + return arrayOfObjects; +}; +