From 332b6525b9b74beb042a15ae6318ac39605a52dc Mon Sep 17 00:00:00 2001 From: denniswangcodes Date: Mon, 1 May 2023 22:16:03 -0700 Subject: [PATCH 01/36] added IRS classification dropdown to new org signup UI --- .../SignUpUserAndNonprofit.tsx | 6 +- client/src/views/Signup.tsx | 26 +- client/src/views/SignupNonProfit.tsx | 599 +++++++++++++++++- server/sample.env | 28 - 4 files changed, 613 insertions(+), 46 deletions(-) delete mode 100644 server/sample.env diff --git a/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx b/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx index 52205be2..66f7ce42 100644 --- a/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx +++ b/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx @@ -182,7 +182,7 @@ export const SignUpUserAndNonprofit = () => { align="left" gutterBottom > - Let's get started. + Let's get started @@ -266,7 +266,7 @@ export const SignUpUserAndNonprofit = () => { label="Legal Name" placeholder="Legal Name" fullWidth - disabled={true} + disabled={false} /> )} /> @@ -438,7 +438,7 @@ export const SignUpUserAndNonprofit = () => { displayEmpty > - Select classification + Select Classification {classifications.map((option, index) => { return ( diff --git a/client/src/views/Signup.tsx b/client/src/views/Signup.tsx index 9b9d48af..845b6a6f 100644 --- a/client/src/views/Signup.tsx +++ b/client/src/views/Signup.tsx @@ -39,33 +39,33 @@ function Signup() { return ( - + {/* Welcome! - + */} - Select your account type. + Account Type - + {/* Already have an account? Log In{' '} - + */} -
- + {/*
*/} + {/* Are you a non-profit organization? - +
*/} - +
-
- + {/*
*/} + {/* Are you an individual citizen? - +
*/} - +
diff --git a/client/src/views/SignupNonProfit.tsx b/client/src/views/SignupNonProfit.tsx index 3a6e2cd7..d3e7ef71 100644 --- a/client/src/views/SignupNonProfit.tsx +++ b/client/src/views/SignupNonProfit.tsx @@ -1,7 +1,602 @@ -import { SignUpUserAndNonprofit } from '../components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit'; +// import { SignUpUserAndNonprofit } from '../components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit'; + +// function SignupNonProfit() { +// return ; +// } + +// export default SignupNonProfit; + +import * as React from 'react'; +import FormControl from '@mui/material/FormControl'; +import Grid from '@mui/material/Grid'; +import Input from '@mui/material/Input'; +import makeStyles from '@mui/styles/makeStyles'; +import Typography from '@mui/material/Typography'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Checkbox from '@mui/material/Checkbox'; +import Button from '@mui/material/Button'; +import type { Theme } from '@mui/material/styles'; +import { placeholderImg } from '../assets/temp'; +import EmailInput from '../components/Users/Auth/EmailInput'; +import FacebookAuthBtn from '../components/Users/Auth/FacebookAuthBtn'; +import GoogleAuthBtn from '../components/Users/Auth/GoogleAuthBtn'; +import PasswordInput from '../components/Users/Auth/PasswordInput'; +import StyledLink from '../components/StyledLink'; +import TextDivider from '../components/TextDivider'; +import routes from '../routes/routes'; +import { UserContext } from '../providers'; +import { APP_API_BASE_URL, US_STATE_NAMES } from '../configs'; +import { Controller, useForm } from 'react-hook-form'; +import { classifications } from '../components/Users/Auth/SignUpUserAndNonprofit/Classifications'; +import { + Box, + Stepper, + Step, + StepLabel, + Select, + MenuItem, + Chip, + Avatar, + TextField, + OutlinedInput, +} from '@mui/material'; + +const useStyles = makeStyles((theme: Theme) => ({ + sideImg: { + backgroundImage: `url("${placeholderImg}")`, + backgroundSize: 'cover', + backgroundPosition: 'center center', + backgroundRepeat: 'no-repeat', + borderTopRightRadius: '15px', + borderBottomRightRadius: '15px', + }, + signUpContainer: { + margin: theme.spacing(5), + }, + button: { + borderRadius: 0, + height: 44, + textTransform: 'none', + backgroundColor: '#C4C4C4', + color: 'white', + }, + header: { + fontWeight: 'bold', + paddingBottom: '40px', + }, + input: { + height: 44, + border: '1px solid #C4C4C4', + borderRadius: 10, + boxSizing: 'border-box', + padding: theme.spacing(1), + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + fontSize: 14, + marginBottom: 20, + }, + label: { + color: '#000000', + fontWeight: 'bold', + textAlign: 'left', + }, + chip: { + boxShadow: '0px 1px 2px rgba(0, 0, 0, 0.25)', + height: 44, + }, +})); + +interface UserSignupData { + firstName: string; + last_name: string; + email: string; + password: string; + accept_terms?: boolean; + email_notification_opt_out?: boolean; +} + +const initialFormData: UserSignupData = { + firstName: '', + last_name: '', + email: '', + password: '', + accept_terms: false, + email_notification_opt_out: false, +}; + +const interests = [ + 'Animal Care & Services', + 'Poverty', + 'Housing & Homeless', + 'Youth & Children', + 'Disaster Relief', + 'Health Care & Welness', + 'Environment & Sustainability', + 'Sports & Recreation', + 'Seniors', + 'Religion, Faith & Spirituality', + 'Civic Engagement', + 'LGTBQIA+', + 'Civil Rights & Advocacy', + 'Military & Veterans', + 'Social Justice', + 'Education & Literacy', + 'Arts & Culture', +]; function SignupNonProfit() { - return ; + const { sideImg, signUpContainer, button, header, input, label, chip } = useStyles(); + const [activeStep, setActiveStep] = React.useState(0); + const [isLoading, setIsLoading] = React.useState(false); + const [emailError, setEmailError] = React.useState(''); + const [formData, setFormData] = React.useState(initialFormData); + const { user, setUser } = React.useContext(UserContext); + const { control } = useForm(); + const steps = [ + { label: 'Basic Information' }, + { label: 'Location' }, + { label: 'Focus Area' }, + { label: 'Profile' }, + ]; + + const makeChips = () => { + return interests.map((interest) => { + return ( + console.log(interest)} + /> + ); + }); + }; + + const makeStateSelectOptions = () => { + return US_STATE_NAMES.map((state) => { + return {state}; + }); + }; + + const handleChange = (evt: React.ChangeEvent): void => { + const { name, value, checked }: { name: string; value: string; checked: boolean } = evt.target; + setFormData((fData) => ({ + ...fData, + [name]: name === 'accept_terms' ? checked : value, + [name]: name === 'email_notification_opt_out' ? checked : value, + })); + }; + + const handleSubmit = async (evt: React.FormEvent) => { + evt.preventDefault(); + setIsLoading(true); + // Backend doesn't need accept_terms. If a user is signed up they have agreed to the terms + delete formData.accept_terms; + const res = await fetch(`${APP_API_BASE_URL}/auth/register`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData), + }); + const data = await res.json(); + setIsLoading(false); + if (data.status === 409) { + setEmailError(data.message); + } else { + setUser(data); + handleNext(); + } + }; + + // handleNext and handleBack are also in SignUpUserAndNonProfit, refactor later + const handleNext = () => { + setActiveStep((prevActiveStep) => prevActiveStep + 1); + }; + + const handleBack = () => { + setActiveStep((prevActiveStep) => prevActiveStep - 1); + }; + + return ( +
+ + + + + + + + {steps.map((step, index) => ( + + Last Step + ) : null + } + > + {step.label} + + + ))} + + + +
+ {/* PAGE ONE ###########################################################*/} + {activeStep === 0 && ( + <> + + Let's get started + + + Sign Up with Google + Sign Up With Facebook + + or + + + + + + + + + + + + + + + ( + <> + + + + )} + /> + {/* + {errors.nonprofit_classification + ? errors.nonprofit_classification.message + : ''} + */} + + + + + + + } + label={ + + } + /> + + } + label={'Opt Out Of Email Notifications'} + /> + + Already have an account? Log In + + + )} + + {/* PAGE TWO ######################################################## */} + {activeStep === 1 && ( + <> + + Tell us about your organization's location + + + Location + + + You can update this information later in the settings of your account. + + + + + + + + + + + + + + + + + + )} + + {/* PAGE THREE ######################################################## */} + {activeStep === 2 && ( + <> + + Tell us about your organization's focus area(s) + + + Focus Area + + + You can update this information later in the settings of your account. + + + + + + + + {makeChips()} + + + + )} + + {/* PAGE FOUR ######################################################## */} + {activeStep === 3 && ( + <> + + Tell us about your organization + + + Profile + + + You can update this information later in the settings of your account. + + + + + + + + + + + + + + Description + + + + + + )} + + {/* PAGE FIVE ######################################################## */} + {/* SHOWN WHEN SIGNUP DONE ######################################################## */} + {activeStep === 4 && ( + <> + + Sign up Complete! + + + Name: {user && user.firstName} {user && user.last_name} + + Email: {user && user.email} + + + Please check your email to finish the identity verification process. Otherwise, + start posting your organization needs. + + + )} + + {activeStep !== 4 && ( + + + + + + {activeStep === 0 && ( + + )} + {activeStep === 1 && ( + + )} + {activeStep === 2 && ( + + )} + {activeStep === 3 && ( + + )} + + + + )} + {/* Placeholder for loading - waiting on UI/UX response as to what they want. */} + {isLoading && Loading} + + + + + {activeStep === 4 && ( + <> + + + + + + + + + )} +
+ ); } export default SignupNonProfit; diff --git a/server/sample.env b/server/sample.env deleted file mode 100644 index 62a7ad9a..00000000 --- a/server/sample.env +++ /dev/null @@ -1,28 +0,0 @@ - -# if you change DATABASE_DB, also change db name in init.sql -MODE=dev -PORT=3001 -DATABASE_HOST=localhost -DATABASE_PORT=5432 -DATABASE_USER=postgres -DATABASE_PASSWORD=your_password -DATABASE_DB=test_db -POSTGRESQL_SSL_CA="" -POSTGRESQL_SSL_CERT="" -POSTGRESQL_SSL_KEY="" -BCRYPT_WORK_FACTOR=10 - -# e2e used when running e2e tests -E2E_DATABASE_DB=e2e_db - -# sockets gateway cors -SOCKET_CORS_ORIGIN="http://localhost:3000" - -# Azure blob storage -AZURE_BLOB_CONNECTION_STR=fake -AZURE_BLOB_CONTAINER=images - -#JWT -JWT_SECRET=foobar -SENDGRID_API_KEY=SG.foobar -FE_DOMAIN=http://localhost:3000 From f854cbcdf26d15b390f64f772352251b04160075 Mon Sep 17 00:00:00 2001 From: denniswangcodes Date: Mon, 8 May 2023 19:28:46 -0700 Subject: [PATCH 02/36] updated steps to Figma design 90% similarity --- client/src/views/SignupNonProfit.tsx | 242 +++++++++++++-------------- 1 file changed, 118 insertions(+), 124 deletions(-) diff --git a/client/src/views/SignupNonProfit.tsx b/client/src/views/SignupNonProfit.tsx index d3e7ef71..bb92742f 100644 --- a/client/src/views/SignupNonProfit.tsx +++ b/client/src/views/SignupNonProfit.tsx @@ -35,7 +35,6 @@ import { StepLabel, Select, MenuItem, - Chip, Avatar, TextField, OutlinedInput, @@ -104,28 +103,8 @@ const initialFormData: UserSignupData = { email_notification_opt_out: false, }; -const interests = [ - 'Animal Care & Services', - 'Poverty', - 'Housing & Homeless', - 'Youth & Children', - 'Disaster Relief', - 'Health Care & Welness', - 'Environment & Sustainability', - 'Sports & Recreation', - 'Seniors', - 'Religion, Faith & Spirituality', - 'Civic Engagement', - 'LGTBQIA+', - 'Civil Rights & Advocacy', - 'Military & Veterans', - 'Social Justice', - 'Education & Literacy', - 'Arts & Culture', -]; - function SignupNonProfit() { - const { sideImg, signUpContainer, button, header, input, label, chip } = useStyles(); + const { sideImg, signUpContainer, button, header, input, label } = useStyles(); const [activeStep, setActiveStep] = React.useState(0); const [isLoading, setIsLoading] = React.useState(false); const [emailError, setEmailError] = React.useState(''); @@ -134,24 +113,11 @@ function SignupNonProfit() { const { control } = useForm(); const steps = [ { label: 'Basic Information' }, - { label: 'Location' }, - { label: 'Focus Area' }, + { label: 'Representative' }, + { label: 'Organization' }, { label: 'Profile' }, ]; - const makeChips = () => { - return interests.map((interest) => { - return ( - console.log(interest)} - /> - ); - }); - }; - const makeStateSelectOptions = () => { return US_STATE_NAMES.map((state) => { return {state}; @@ -237,6 +203,14 @@ function SignupNonProfit() { > Let's get started + + Already have an account? Log In + Sign Up with Google Sign Up With Facebook @@ -323,62 +297,6 @@ function SignupNonProfit() {
- - - - } - label={ - - } - /> - - } - label={'Opt Out Of Email Notifications'} - /> - - Already have an account? Log In - )} @@ -392,31 +310,58 @@ function SignupNonProfit() { component="h1" align="left" > - Tell us about your organization's location + Tell us about yourself - Location - - - You can update this information later in the settings of your account. + Representative Information - + - - - - + First Name + - + Last Name + - - + + Role + + + + + + + } + label={'Opt Out Of Email Notifications'} + /> )} @@ -430,24 +375,49 @@ function SignupNonProfit() { component="h1" align="left" > - Tell us about your organization's focus area(s) + Tell us about your organization - Focus Area - - - You can update this information later in the settings of your account. + Contact Information - + - + Street address + + + + City + + + + State + + + + Zip Code + + + Online Information + - {makeChips()} + Website + + + + Instagram + + + + Facebook + + + + Twitter + @@ -466,11 +436,9 @@ function SignupNonProfit() { Tell us about your organization - Profile - - - You can update this information later in the settings of your account. + Add an image + Upload an organization logo (optional) @@ -492,7 +460,10 @@ function SignupNonProfit() { - Description + Write a description + + + You can update this information later in your account settings + + } + label={ + + } + /> )} From 03813acd3325d8f807022a59dc5cfc8b60cc8a6d Mon Sep 17 00:00:00 2001 From: denniswangcodes Date: Mon, 8 May 2023 21:32:39 -0700 Subject: [PATCH 03/36] minor text rearrangement --- client/src/views/SignupNonProfit.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/views/SignupNonProfit.tsx b/client/src/views/SignupNonProfit.tsx index bb92742f..e785b550 100644 --- a/client/src/views/SignupNonProfit.tsx +++ b/client/src/views/SignupNonProfit.tsx @@ -217,7 +217,7 @@ function SignupNonProfit() { or - + - + - + Date: Wed, 7 Jun 2023 23:41:45 -0700 Subject: [PATCH 04/36] repurposed 306-sign-in-modal modal logic for signup.tsx --- client/src/views/Signup.tsx | 161 ++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 60 deletions(-) diff --git a/client/src/views/Signup.tsx b/client/src/views/Signup.tsx index 845b6a6f..02782f6b 100644 --- a/client/src/views/Signup.tsx +++ b/client/src/views/Signup.tsx @@ -1,75 +1,116 @@ import * as React from 'react'; import { Link } from 'react-router-dom'; +import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; import makeStyles from '@mui/styles/makeStyles'; -import { Grid, Container, Button } from '@mui/material'; - +import { Grid, Button } from '@mui/material'; import type { Theme } from '@mui/material/styles'; - +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; import routes from '../routes/routes'; +// import { Container } from '@mui/material'; keep for future commits +// import StyledLink from '../components/StyledLink'; +// import TextDivider from '../components/TextDivider'; +// import DialogContentText from '@mui/material/DialogContentText'; + +const useStyles = makeStyles((theme: Theme) => { + const xPadding = 12; + const yPadding = 6; + const yMargin = 8; -const useStyles = makeStyles((theme: Theme) => ({ - imageBackground: { - width: '200px', - height: '200px', - background: '#C4C4C4', - borderRadius: '130px', - marginBottom: '1rem', - }, - linkText: { - color: theme.palette.text.primary, - textDecoration: 'none', - }, - formBox: { - textAlign: 'center', - width: '100%', - }, - positionOptions: { - marginLeft: '20%', - marginTop: '5rem', - alignContent: 'center', - }, - caption: { - width: '200px', - }, -})); + return { + imageBackground: { + width: '200px', + height: '200px', + background: '#C4C4C4', + borderRadius: '130px', + marginBottom: '1rem', + }, + linkText: { + color: theme.palette.text.primary, + textDecoration: 'none', + }, + formBox: { + textAlign: 'center', + width: '100%', + }, + positionOptions: { + marginLeft: '20%', + marginTop: '5rem', + alignContent: 'center', + }, + caption: { + width: '200px', + }, + paper: { + maxWidth: 821 - theme.spacing(xPadding), + maxHeight: 732 - theme.spacing(yPadding), + borderRadius: 10, + marginTop: theme.spacing(yMargin), + marginBottom: theme.spacing(yMargin), + paddingTop: theme.spacing(yPadding), + paddingBottom: theme.spacing(yPadding), + paddingLeft: theme.spacing(xPadding), + paddingRight: theme.spacing(xPadding), + margin: 'auto', + }, + header: { fontWeight: 'bold', marginBottom: 68 }, + button: { + borderRadius: 0, + height: 62, + textTransform: 'none', + }, + }; +}); function Signup() { const classes = useStyles(); - return ( - - {/* - Welcome! - */} - - Account Type - - {/* - Already have an account? Log In{' '} - */} + const [open, setOpen] = React.useState(true); + const onClose = (e: any, reason: string) => { + if (reason !== 'backdropClick') { + setOpen(false); + } + }; + + const buttonClose = () => { + setOpen(false); + }; - - - {/*
*/} - {/* - Are you a non-profit organization? - */} - - - -
- - {/*
*/} - {/* - Are you an individual citizen? - */} - - - -
-
-
+ return ( +
+ +
+ + Welcome! + + {/* */} + + Account Type + + + + + + + + + + + + + + {/* */} + + + + + +
+
+
); } From a7a1ada975bebb3a9a09d49ba1edd9c9932600df Mon Sep 17 00:00:00 2001 From: denniswangcodes Date: Wed, 7 Jun 2023 23:51:30 -0700 Subject: [PATCH 05/36] added back sample.env file --- server/sample.env | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 server/sample.env diff --git a/server/sample.env b/server/sample.env new file mode 100644 index 00000000..90e47caf --- /dev/null +++ b/server/sample.env @@ -0,0 +1,29 @@ + +# if you change DATABASE_DB, also change db name in init.sql +NODE_ENV=development +PORT=3001 +DATABASE_HOST=localhost +DATABASE_PORT=5432 +DATABASE_USER=postgres +DATABASE_PASSWORD=your_password +DATABASE_DB=test_db +POSTGRESQL_SSL_CA="" +POSTGRESQL_SSL_CERT="" +POSTGRESQL_SSL_KEY="" +BCRYPT_WORK_FACTOR=10 +DB_LOGGING=true + +# e2e used when running e2e tests +E2E_DATABASE_DB=e2e_db + +# sockets gateway cors +SOCKET_CORS_ORIGIN="http://localhost:3000" + +# Azure blob storage +AZURE_BLOB_CONNECTION_STR=fake +AZURE_BLOB_CONTAINER=images + +#JWT +JWT_SECRET=foobar +SENDGRID_API_KEY=SG.foobar +FE_DOMAIN=http://localhost:3000 From 97e0cc9ae105fc49fc8c787cdf48157db5b550b5 Mon Sep 17 00:00:00 2001 From: denniswangcodes Date: Thu, 8 Jun 2023 00:01:44 -0700 Subject: [PATCH 06/36] Put back old code in signupuserandnonprofit.tsk to resolve conflict --- .../SignUpUserAndNonprofit.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx b/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx index 66f7ce42..89cd0005 100644 --- a/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx +++ b/client/src/components/Users/Auth/SignUpUserAndNonprofit/SignUpUserAndNonprofit.tsx @@ -261,13 +261,22 @@ export const SignUpUserAndNonprofit = () => { control={control} defaultValue={''} render={({ field }) => ( - + <> + + State + + { + if (!errors.state) { + console.log('add validation here'); + } + }} + error={!!errors.state?.message} + /> + )} /> {orgValidateEinQuery.isSuccess && !errors.ein && ( From 2a12165b4b6ec57720bb5ca74c56fdd0301a99fb Mon Sep 17 00:00:00 2001 From: etokruto Date: Sun, 11 Jun 2023 15:26:58 -0700 Subject: [PATCH 07/36] Modal working, test modal opens closes successfully --- client/src/App.tsx | 43 ++++--- client/src/components/Header.tsx | 32 ++++- client/src/components/Modal.tsx | 29 +++++ client/src/components/Modals/SignInModal.tsx | 18 +++ client/src/components/Modals/SignUpModal.tsx | 17 +++ client/src/providers/ModalProvider.tsx | 43 +++++++ client/src/providers/index.ts | 1 + client/src/views/Login.tsx | 129 ++++++++++++------- 8 files changed, 241 insertions(+), 71 deletions(-) create mode 100644 client/src/components/Modal.tsx create mode 100644 client/src/components/Modals/SignInModal.tsx create mode 100644 client/src/components/Modals/SignUpModal.tsx create mode 100644 client/src/providers/ModalProvider.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index b72c6468..3fe00595 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,11 +4,13 @@ import { BrowserRouter } from 'react-router-dom'; import { Grid, ThemeProvider, StyledEngineProvider } from '@mui/material'; import theme from './theme'; -import Footer from './components/Footer'; import Header from './components/Header'; import Main from './views/Main'; -import { UserProvider } from './providers'; +import Footer from './components/Footer'; +import Modal from './components/Modal'; +import { UserProvider } from './providers'; +import { ModalProvider } from './providers/ModalProvider'; import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; @@ -28,24 +30,27 @@ function App(): JSX.Element { - { - // intentionally left empty callback to block the default browser prompt. - }} - > - + { + // intentionally left empty callback to block the default browser prompt. + }} > -
-
-