From 5514856462425de02c2fb8a2c5a9ab8009da42f5 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 30 Oct 2023 23:49:51 -0700 Subject: [PATCH 001/263] Establishing UI foundation --- .../CivicProfileForms/BasicInfo.jsx | 131 +++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index d37b16c2c..66ef0be64 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -1,6 +1,131 @@ -import { Typography } from '@mui/material'; -import React from 'react'; +// React Imports +import React, { useState } from 'react'; +// Material UI Imports +import Button from '@mui/material/Button'; +import FormControl from '@mui/material/FormControl'; +import FormHelperText from '@mui/material/FormHelperText'; +import Grid from '@mui/material/Grid'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import Select from '@mui/material/Select'; +import TextField from '@mui/material/TextField'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +// Component Imports +import { FormSection } from '../Form'; -const BasicInfo = () => Basic Info; +const BasicInfo = () => { + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [age, setAge] = useState(''); + const [gender, setGender] = useState(''); + + const handleFirstNameChange = (event) => { + setFirstName(event.target.value); + }; + + const handleLastNameChange = (event) => { + setLastName(event.target.value); + }; + + const handleAgeChange = (event) => { + setAge(event.target.value); + }; + + const handleGenderChange = (event) => { + setGender(event.target.value); + }; + + /* eslint-disable jsx-a11y/label-has-associated-control */ + return ( + + + + + + + + + + + + + + YYYY-MM-DD + + + + + Gender + + + + + + + + + + + + ); + /* eslint-disable jsx-a11y/label-has-associated-control */ +}; export default BasicInfo; From 1c08e7abfaf96fb0653f55b267a9e622bf8d224c Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 31 Oct 2023 15:56:30 -0700 Subject: [PATCH 002/263] Adding field clearing functionality --- .../CivicProfileForms/BasicInfo.jsx | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 66ef0be64..c4c20ffa7 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -1,40 +1,49 @@ // React Imports import React, { useState } from 'react'; +// Inrupt Library Imports +// import { useSession } from '@hooks'; // Material UI Imports +// import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; +// import Checkbox from '@mui/material/Checkbox'; +import CheckIcon from '@mui/icons-material/Check'; +import ClearIcon from '@mui/icons-material/Clear'; +// import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import FormControl from '@mui/material/FormControl'; +// import FormControlLabel from '@mui/material/FormControlLabel'; import FormHelperText from '@mui/material/FormHelperText'; import Grid from '@mui/material/Grid'; +// import IconButton from '@mui/material/IconButton'; +// import InputAdornment from '@mui/material/InputAdornment'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; +// import Select, { SelectChangeEvent } from '@mui/material/Select'; import TextField from '@mui/material/TextField'; +// import Typography from '@mui/material/Typography'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +// Utility Imports +// import { sendMessageTTL, getMessageTTL } from '@utils'; +// Context Imports +// import { MessageContext, SignedInUserContext } from '@contexts'; +// Custom Hook Imports +// import useNotification from '@hooks/useNotification'; // Component Imports import { FormSection } from '../Form'; const BasicInfo = () => { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); - const [age, setAge] = useState(''); + const [age, setAge] = useState(null); const [gender, setGender] = useState(''); - const handleFirstNameChange = (event) => { - setFirstName(event.target.value); - }; - - const handleLastNameChange = (event) => { - setLastName(event.target.value); - }; - - const handleAgeChange = (event) => { - setAge(event.target.value); - }; - - const handleGenderChange = (event) => { - setGender(event.target.value); + const clearForm = () => { + setFirstName(''); + setLastName(''); + setAge(null); + setGender(''); }; /* eslint-disable jsx-a11y/label-has-associated-control */ @@ -50,7 +59,7 @@ const BasicInfo = () => { autoComplete="given-name" variant="standard" value={firstName} - onChange={handleFirstNameChange} + onChange={(newFirstName) => setFirstName(newFirstName.target.value)} /> @@ -62,7 +71,7 @@ const BasicInfo = () => { autoComplete="family-name" variant="standard" value={lastName} - onChange={handleLastNameChange} + onChange={(newLastName) => setLastName(newLastName.target.value)} /> @@ -74,7 +83,7 @@ const BasicInfo = () => { label="Date of birth" type="date" value={age} - onChange={handleAgeChange} + onChange={(newAge) => setAge(newAge)} /> YYYY-MM-DD @@ -88,7 +97,7 @@ const BasicInfo = () => { id="hmis-basic-info-gender" value={gender} label="Gender" - onChange={handleGenderChange} + onChange={(newGender) => setGender(newGender.target.value)} > Female Male @@ -105,10 +114,12 @@ const BasicInfo = () => { variant="contained" type="submit" color="secondary" + startIcon={} fullWidth sx={{ borderRadius: '20px' }} + onClick={clearForm} > - Clear Form + Cancel @@ -116,6 +127,7 @@ const BasicInfo = () => { variant="contained" type="submit" color="primary" + startIcon={} fullWidth sx={{ borderRadius: '20px' }} > From 73754fa8abd4f95c9441ba814d1247bd73319d3c Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 31 Oct 2023 16:00:21 -0700 Subject: [PATCH 003/263] Beginning JSDoc for component --- .../CivicProfileForms/BasicInfo.jsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index c4c20ffa7..5edbf3882 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -1,38 +1,30 @@ // React Imports import React, { useState } from 'react'; -// Inrupt Library Imports -// import { useSession } from '@hooks'; // Material UI Imports -// import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; -// import Checkbox from '@mui/material/Checkbox'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; -// import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import FormControl from '@mui/material/FormControl'; -// import FormControlLabel from '@mui/material/FormControlLabel'; import FormHelperText from '@mui/material/FormHelperText'; import Grid from '@mui/material/Grid'; -// import IconButton from '@mui/material/IconButton'; -// import InputAdornment from '@mui/material/InputAdornment'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; -// import Select, { SelectChangeEvent } from '@mui/material/Select'; import TextField from '@mui/material/TextField'; -// import Typography from '@mui/material/Typography'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -// Utility Imports -// import { sendMessageTTL, getMessageTTL } from '@utils'; -// Context Imports -// import { MessageContext, SignedInUserContext } from '@contexts'; -// Custom Hook Imports -// import useNotification from '@hooks/useNotification'; // Component Imports import { FormSection } from '../Form'; +/** + * BasicInfo Component - Component that generates the form for entering + * basic user information in accordance with HMIS principles + * + * @memberof CivicProfileForms + * @name BasicInfo + * @returns {React.JSX.Element} The BasicInfo Component + */ const BasicInfo = () => { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); From 375c3e7acdd217843de698d39c5c660fde6df80d Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 13 Nov 2023 21:21:09 -0800 Subject: [PATCH 004/263] Testing WIP changes from #515 --- .../CivicProfileForms/BasicInfo.jsx | 204 ++++++++++-------- 1 file changed, 110 insertions(+), 94 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 5edbf3882..cfbc25231 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -1,5 +1,5 @@ // React Imports -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; // Material UI Imports import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; @@ -14,6 +14,8 @@ import TextField from '@mui/material/TextField'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +// Hook Imports +import { useCivicProfile } from '@hooks'; // Component Imports import { FormSection } from '../Form'; @@ -26,107 +28,121 @@ import { FormSection } from '../Form'; * @returns {React.JSX.Element} The BasicInfo Component */ const BasicInfo = () => { - const [firstName, setFirstName] = useState(''); - const [lastName, setLastName] = useState(''); - const [age, setAge] = useState(null); - const [gender, setGender] = useState(''); + const { data, add, isSuccess } = useCivicProfile(); + const [formData, setFormData] = useState({ + firstName: '', + lastName: '', + age: '', + gender: '' + }); - const clearForm = () => { - setFirstName(''); - setLastName(''); - setAge(null); - setGender(''); + useEffect(() => { + if (isSuccess) { + setFormData((prevFormData) => ({ ...prevFormData, ...data })); + } + }, [isSuccess, data]); + + const handleChange = (event) => { + const { name, value } = event.target; + setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); + }; + const handleSubmit = (e) => { + e.preventDefault(); + if (!isSuccess) { + return; + } + add(formData); }; /* eslint-disable jsx-a11y/label-has-associated-control */ return ( - - - setFirstName(newFirstName.target.value)} - /> - - - setLastName(newLastName.target.value)} - /> - - - - - setAge(newAge)} - /> - - YYYY-MM-DD - - - - - Gender - + Female + Male + Transgender male to female + Transgender female to male + Doesn't identify as male, female or transgender + Don't know + Decline to answer + + + + + - - - + Cancel + + + + + - + ); /* eslint-disable jsx-a11y/label-has-associated-control */ From 9da15451d04b72940d3151bc4031b51e6cc5e7bc Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 13 Nov 2023 21:56:15 -0800 Subject: [PATCH 005/263] Applying HMIS terminology --- .../CivicProfileForms/BasicInfo.jsx | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index cfbc25231..35263f2c1 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -20,8 +20,7 @@ import { useCivicProfile } from '@hooks'; import { FormSection } from '../Form'; /** - * BasicInfo Component - Component that generates the form for entering - * basic user information in accordance with HMIS principles + * BasicInfo Component - A form to fill out basic user info * * @memberof CivicProfileForms * @name BasicInfo @@ -30,10 +29,10 @@ import { FormSection } from '../Form'; const BasicInfo = () => { const { data, add, isSuccess } = useCivicProfile(); const [formData, setFormData] = useState({ - firstName: '', - lastName: '', - age: '', - gender: '' + legalFirstName: '', + legalLastName: '', + legalDOB: '', + legalGender: '' }); useEffect(() => { @@ -58,40 +57,43 @@ const BasicInfo = () => { return (
- + YYYY-MM-DD @@ -101,10 +103,11 @@ const BasicInfo = () => { Gender - Female - Male - Transgender male to female - Transgender female to male - Doesn't identify as male, female or transgender - Don't know - Decline to answer - - - - - - - - + + + - +
); }; diff --git a/test/components/CivicProfileForms/BasicInfo.test.jsx b/test/components/CivicProfileForms/BasicInfo.test.jsx index c63cf1a03..0f3dea34e 100644 --- a/test/components/CivicProfileForms/BasicInfo.test.jsx +++ b/test/components/CivicProfileForms/BasicInfo.test.jsx @@ -18,7 +18,7 @@ describe('Basic info form', () => { it('renders', () => { useCivicProfile.mockReturnValue({ data: {}, isSuccess: true }); const { getByRole } = render(); - const firstNameField = getByRole('textbox', { name: 'First Name:' }); + const firstNameField = getByRole('input', { name: 'First Name:' }); expect(firstNameField).not.toBeNull(); }); @@ -28,15 +28,15 @@ describe('Basic info form', () => { const basicInfoProfile = { firstName: 'John', lastName: 'Doe', - dateOfBirth: '1980-12-12', + dateOfBirth: '1980-12-15', gender: 'Male' }; useCivicProfile.mockReturnValue({ add: mockAdd, isSuccess: true }); const { getByRole } = render(); - const firstNameField = getByRole('textbox', { name: 'First Name:' }); - const lastNameField = getByRole('textbox', { name: 'Last Name:' }); - const dateOfBirthField = getByRole('textbox', { name: 'Date of Birth:' }); - const genderField = getByRole('textbox', { name: 'Gender:' }); + const firstNameField = getByRole('textbox', { name: 'Legal First Name' }); + const lastNameField = getByRole('textbox', { name: 'Legal Last Name' }); + const dateOfBirthField = getByRole('textbox', { name: 'Date of Birth' }); + const genderField = getByRole('textbox', { name: 'Gender' }); const submitButton = getByRole('button'); await user.type(firstNameField, basicInfoProfile.firstName); await user.type(lastNameField, basicInfoProfile.lastName); From c9bce762d78da11125cd5587312f21d0f3d9903b Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 20 Nov 2023 20:49:10 -0800 Subject: [PATCH 009/263] Resolving a few errors, working on more --- .../CivicProfileForms/BasicInfo.jsx | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index c25a66445..96c3ec040 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -29,10 +29,10 @@ import { FormSection } from '../Form'; const BasicInfo = () => { const { data, add, isSuccess } = useCivicProfile(); const [formData, setFormData] = useState({ - firstName: '', - lastName: '', - dateOfBirth: '', - gender: '' + legalFirstName: '', + legalLastName: '', + legalDOB: '', + legalGender: '' }); useEffect(() => { @@ -78,9 +78,10 @@ const BasicInfo = () => { id="hmis-basic-info-last-name" name="legalLastName" label="Legal Last name" + onChange={handleChange} + value={formData.legalLastName} margin="normal" fullWidth - value={formData.legalLastName} /> @@ -89,10 +90,11 @@ const BasicInfo = () => { YYYY-MM-DD @@ -102,10 +104,13 @@ const BasicInfo = () => { Gender ))} + ); }; From ac5949eb5fbf17b7a077b0b4444f2e25c28412b1 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 3 Mar 2024 18:35:51 -0800 Subject: [PATCH 013/263] Adding notification for successful image upload --- src/components/Profile/ProfileImageField.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Profile/ProfileImageField.jsx b/src/components/Profile/ProfileImageField.jsx index a8db2eb02..032a1cd0a 100644 --- a/src/components/Profile/ProfileImageField.jsx +++ b/src/components/Profile/ProfileImageField.jsx @@ -45,7 +45,7 @@ const ProfileImageField = ({ loadProfileData, contactProfile }) => { const updatedProfileData = await fetchProfileInfo(session.info.webId); localStorage.setItem('profileImage', updatedProfileData.profileInfo.profileImage); setProfileImg(updatedProfileData.profileInfo.profileImage); - + addNotification('success', `Profile image added.`); loadProfileData(); } }; From aa4e4f3925d7d82ae5b69e3d5b811df002ad4ca6 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:44:13 -0700 Subject: [PATCH 014/263] Added OIDC Provider Dropdown --- src/components/Modals/AddContactModal.jsx | 33 ++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 763e03d43..efc7629ce 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -14,13 +14,19 @@ import FormControl from '@mui/material/FormControl'; import IconButton from '@mui/material/IconButton'; import InputAdornment from '@mui/material/InputAdornment'; import TextField from '@mui/material/TextField'; +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import InputLabel from '@mui/material/InputLabel'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; // Custom Hook Imports import useNotification from '@hooks/useNotification'; // Component Imports +import { ENV } from '@constants'; import { FormSection } from '../Form'; +// Constant Imports + // @memberof Modals // @name renderWebId // @param {string} username - Username to convert into a webId @@ -52,12 +58,19 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod const [processing, setProcessing] = useState(false); const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + const [oidcProviders] = useState(ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', ')); + const [Oidc, setOIDC] = React.useState(''); const clearInputFields = () => { setUserGivenName(''); setUserFamilyName(''); setWebId(''); setInvalidWebId(false); + setOIDC(''); + }; + + const handleOidcSelection = (e) => { + setOIDC(e.target.value); }; const handleAddContact = async (event) => { @@ -72,6 +85,8 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) }; + console.log(oidcProviders); + try { await getWebIdDataset(userObject.webId); await addContact(userObject); @@ -121,7 +136,23 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod onChange={(e) => setUserFamilyName(e.target.value)} fullWidth /> - + + OIDC Provider + + Date: Mon, 11 Mar 2024 13:30:57 -0700 Subject: [PATCH 015/263] Added username field and enabled/disabled WebID section based on OIDC Selection. --- src/components/Modals/AddContactModal.jsx | 78 +++++++++++++++-------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index efc7629ce..0df9ae5eb 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -55,10 +55,12 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod const [userFamilyName, setUserFamilyName] = useState(''); const [webId, setWebId] = useState(''); const [invalidWebId, setInvalidWebId] = useState(false); + const [userName, setUserName] = useState(''); + const [customWebID, setCustomWebID] = useState(false); const [processing, setProcessing] = useState(false); const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); - const [oidcProviders] = useState(ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', ')); + const [oidcProviders] = useState([...ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', '), 'Other']); const [Oidc, setOIDC] = React.useState(''); const clearInputFields = () => { @@ -70,6 +72,11 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod }; const handleOidcSelection = (e) => { + if (e.target.value === 'Other') { + setCustomWebID(true); + } else { + setCustomWebID(false); + } setOIDC(e.target.value); }; @@ -153,33 +160,48 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod ))} - { - setWebId(e.target.value); - }} - error={invalidWebId} - label={invalidWebId ? 'Error' : ''} - // helperText for invalidWebId === false is ' ' and not '' is to - // prevent the field from stretching when helperText disappears - helperText={invalidWebId ? 'Invalid WebId.' : ' '} - fullWidth - InputProps={{ - endAdornment: ( - - - - - - ) - }} - /> + + + setUserName(e.target.value)} + fullWidth + autoFocus + /> + + {customWebID && ( + { + setWebId(e.target.value); + }} + error={invalidWebId} + label={invalidWebId ? 'Error' : ''} + // helperText for invalidWebId === false is ' ' and not '' is to + // prevent the field from stretching when helperText disappears + helperText={invalidWebId ? 'Invalid WebId.' : ' '} + fullWidth + InputProps={{ + endAdornment: ( + + + + + + ) + }} + /> + )} Date: Tue, 12 Mar 2024 14:31:35 -0700 Subject: [PATCH 016/263] Remove username when entering Custom WebID --- src/components/Modals/AddContactModal.jsx | 48 ++++++++++++++--------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 0df9ae5eb..faca89a42 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -69,6 +69,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod setWebId(''); setInvalidWebId(false); setOIDC(''); + setCustomWebID(false); }; const handleOidcSelection = (e) => { @@ -85,14 +86,21 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod setProcessing(true); const { addUserGivenName, addUserFamilyName, addWebId } = event.target.elements; + let userObject; - const userObject = { - webId: addWebId.value.trim(), - ...(addUserGivenName.value && { givenName: addUserGivenName.value.trim() }), - ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) - }; - - console.log(oidcProviders); + if (customWebID) { + userObject = { + webId: addWebId.value.trim(), + ...(addUserGivenName.value && { givenName: addUserGivenName.value.trim() }), + ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) + }; + } else { + userObject = { + webId: addWebId.value.trim(), + ...(addUserGivenName.value && { givenName: addUserGivenName.value.trim() }), + ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) + }; + } try { await getWebIdDataset(userObject.webId); @@ -161,18 +169,20 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod - - setUserName(e.target.value)} - fullWidth - autoFocus - /> - + {!customWebID && ( + + setUserName(e.target.value)} + fullWidth + autoFocus + /> + + )} {customWebID && ( Date: Tue, 12 Mar 2024 17:52:02 -0700 Subject: [PATCH 017/263] 351 add relationship info (#505) * add relationship (need to clean up later) * use getPodUrlAll * clean up * save quote-unquote progress * add relationship and relationship status, exclude podUrl from makeIntoThing * clean up * do some requested changes * jsdoc change * jsdoc line * change role constant --------- Co-authored-by: Ka Hung Lee --- src/components/Modals/AddContactModal.jsx | 2 ++ src/constants/rdf_predicates.js | 4 +++- src/constants/relationship_status.js | 8 ++++++++ src/constants/relationships.js | 8 ++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/constants/relationship_status.js create mode 100644 src/constants/relationships.js diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 763e03d43..ae4336941 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -169,6 +169,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod setShowAddContactModal(false); }} fullWidth + sx={{ borderRadius: '20px' }} > Cancel @@ -179,6 +180,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod endIcon={} type="submit" fullWidth + sx={{ borderRadius: '20px' }} > Add Contact diff --git a/src/constants/rdf_predicates.js b/src/constants/rdf_predicates.js index b25c14f03..44a971452 100644 --- a/src/constants/rdf_predicates.js +++ b/src/constants/rdf_predicates.js @@ -32,7 +32,9 @@ const RDF_PREDICATES = { nickname: FOAF.nick, dateCreated: 'https://schema.org/dateCreated', propertyValue: 'https://schema.org/PropertyValue', - value: 'https://schema.org/value' + value: 'https://schema.org/value', + role: 'https://schema.org/roleName', + status: 'https://schema.org/status' }; export default RDF_PREDICATES; diff --git a/src/constants/relationship_status.js b/src/constants/relationship_status.js new file mode 100644 index 000000000..13da9c6c3 --- /dev/null +++ b/src/constants/relationship_status.js @@ -0,0 +1,8 @@ +const RELATIONSHIP_STATUS = { + blank: '', + active: 'active', + archive: 'archive', + other: 'other' +}; + +export default RELATIONSHIP_STATUS; diff --git a/src/constants/relationships.js b/src/constants/relationships.js new file mode 100644 index 000000000..82500ea7d --- /dev/null +++ b/src/constants/relationships.js @@ -0,0 +1,8 @@ +const RELATIONSHIP_TYPE = { + blank: '', + client: 'Client', + caseManagement: 'Case Management', + associatedOrg: 'Associated Organization' +}; + +export default RELATIONSHIP_TYPE; From 4816f9692b50d7f3d846b305b2e29fccb59f757e Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 12 Mar 2024 19:20:14 -0700 Subject: [PATCH 018/263] Fixing date input not being recognized --- src/components/CivicProfileForms/BasicInfo.jsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 14cac0c4f..476961b5a 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -31,7 +31,7 @@ const BasicInfo = () => { const [formData, setFormData] = useState({ legalFirstName: '', legalLastName: '', - legalDOB: '', + legalDOB: null, legalGender: '' }); @@ -42,9 +42,17 @@ const BasicInfo = () => { }, [isSuccess, data]); const handleChange = (event) => { - const { name, value } = event.target; - setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); + if (event && event.target) { + const { name, value } = event.target; + setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); + } else { + setFormData({ + ...formData, + legalDOB: event + }); + } }; + const handleSubmit = (e) => { e.preventDefault(); if (!isSuccess) { @@ -52,6 +60,7 @@ const BasicInfo = () => { } add(formData); }; + const handleClear = () => { setFormData({ legalFirstName: '', legalLastName: '', legalDOB: '', legalGender: '' }); }; From 2f28c174726f953291bba64594ffa636ffc94ae0 Mon Sep 17 00:00:00 2001 From: Andy Williams <83156697+andycwilliams@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:47:55 -0700 Subject: [PATCH 019/263] Update src/components/CivicProfileForms/BasicInfo.jsx Co-authored-by: Tim Standen <37914436+timbot1789@users.noreply.github.com> --- src/components/CivicProfileForms/BasicInfo.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 476961b5a..d432e3500 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -129,7 +129,7 @@ const BasicInfo = () => { Male Transgender male to female Transgender female to male - Doesn't identify as male, female or transgender + Don't identify as male, female or transgender Don't know Decline to answer From 1e13721a716430ac2374e04a1161d3621b836a4d Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 13 Mar 2024 14:54:17 -0700 Subject: [PATCH 020/263] Resolving some testing errors --- src/components/CivicProfileForms/BasicInfo.jsx | 8 +++++--- test/components/CivicProfileForms/BasicInfo.test.jsx | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 476961b5a..d896bdd2b 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -5,7 +5,6 @@ import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; import FormControl from '@mui/material/FormControl'; -import FormHelperText from '@mui/material/FormHelperText'; import Grid from '@mui/material/Grid'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; @@ -110,7 +109,6 @@ const BasicInfo = () => { views={['year', 'month', 'day']} /> - YYYY-MM-DD @@ -129,7 +127,7 @@ const BasicInfo = () => { Male Transgender male to female Transgender female to male - Doesn't identify as male, female or transgender + Don't identify as male, female or transgender Don't know Decline to answer @@ -139,11 +137,13 @@ const BasicInfo = () => { @@ -152,11 +152,13 @@ const BasicInfo = () => { diff --git a/test/components/CivicProfileForms/BasicInfo.test.jsx b/test/components/CivicProfileForms/BasicInfo.test.jsx index 09e1480eb..9b8a40a1d 100644 --- a/test/components/CivicProfileForms/BasicInfo.test.jsx +++ b/test/components/CivicProfileForms/BasicInfo.test.jsx @@ -35,13 +35,15 @@ describe('Basic info form', () => { const { getByRole } = render(); const firstNameField = getByRole('textbox', { name: 'Legal first name' }); const lastNameField = getByRole('textbox', { name: 'Legal last name' }); - const dateOfBirthField = getByRole('textbox', { name: 'Date of birth' }); - const genderField = getByRole('textbox', { name: 'Gender' }); - const submitButton = getByRole('button'); + const dateOfBirthField = getByRole('textbox', { name: 'Choose date' }); + const genderField = getByRole('combobox', { name: 'Gender' }); + const clearButton = getByRole('button', { name: 'Clear button' }); + const submitButton = getByRole('button', { name: 'Submit button' }); await user.type(firstNameField, basicInfoProfile.firstName); await user.type(lastNameField, basicInfoProfile.lastName); - await user.type(dateOfBirthField, basicInfoProfile.dateOfBirth); - await user.type(genderField, basicInfoProfile.gender); + await userEvent.type(dateOfBirthField, basicInfoProfile.dateOfBirth); + await userEvent.type(genderField, `${basicInfoProfile.gender}{enter}`); + await user.click(clearButton); await user.click(submitButton); expect(mockAdd).toBeCalledWith(basicInfoProfile); }); From e983684892bd8e632385a5f8a6aa16331eb26424 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 15 Mar 2024 19:53:17 -0700 Subject: [PATCH 021/263] Returning helper text --- src/components/CivicProfileForms/BasicInfo.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index d896bdd2b..354022c53 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -5,6 +5,7 @@ import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; import FormControl from '@mui/material/FormControl'; +import FormHelperText from '@mui/material/FormHelperText'; import Grid from '@mui/material/Grid'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; @@ -109,6 +110,7 @@ const BasicInfo = () => { views={['year', 'month', 'day']} /> + YYYY-MM-DD From 23be0f0ebc18f863cb7f6187595b5ea48963d3d5 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sun, 17 Mar 2024 10:02:33 -0700 Subject: [PATCH 022/263] Fill string based on OIDC provider and username --- src/components/Modals/AddContactModal.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index faca89a42..0af3bbef9 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -63,6 +63,14 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod const [oidcProviders] = useState([...ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', '), 'Other']); const [Oidc, setOIDC] = React.useState(''); + const oidcForm = { + 'http://localhost:3000/': 'http://localhost:3000/user/profile/card#me', + 'https://opencommons.net/': 'http://opencommons.net/user/profile/card#me', + 'https://solidcommunity.net/': 'https://user.solidcommunity.net/profile/card#me.', + 'https://login.inrupt.com/': 'https://id.inrupt.com/user', + 'https://inrupt.net/': 'https://id.inrupt.com/user' + }; + const clearInputFields = () => { setUserGivenName(''); setUserFamilyName(''); @@ -70,6 +78,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod setInvalidWebId(false); setOIDC(''); setCustomWebID(false); + setUserName(''); }; const handleOidcSelection = (e) => { @@ -96,7 +105,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod }; } else { userObject = { - webId: addWebId.value.trim(), + webId: oidcForm[Oidc].replace('user', userName.trim()).trim(), ...(addUserGivenName.value && { givenName: addUserGivenName.value.trim() }), ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) }; From 8f2438c9a83f3644ab5c901b1fb59cf754944844 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Mon, 18 Mar 2024 18:50:29 -0700 Subject: [PATCH 023/263] Fixed the AddContactModal test --- src/components/Modals/AddContactModal.jsx | 1 + test/components/Modals/AddContactModal.test.jsx | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index b234ada45..959bb9bb7 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -167,6 +167,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod id="demo-multiple-name" value={Oidc} label="OIDC Provider" + data-testid="select-oidc" onChange={handleOidcSelection} fullWidth > diff --git a/test/components/Modals/AddContactModal.test.jsx b/test/components/Modals/AddContactModal.test.jsx index 9a74167d8..80ed0d40d 100644 --- a/test/components/Modals/AddContactModal.test.jsx +++ b/test/components/Modals/AddContactModal.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, getByRole as testGetByRole } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; import { AddContactModal } from '@components/Modals'; @@ -60,6 +60,10 @@ describe('add contact', () => { {}} showAddContactModal addContact={mockAdd} /> ); + await userEvent.click(testGetByRole(screen.getByTestId('select-oidc'), 'combobox')); + + await userEvent.click(await screen.findByRole('option', { name: 'Other' })); + const givenName = screen.getByRole('textbox', { name: 'First/given name (Optional)' }); const familyName = screen.getByRole('textbox', { name: 'Last/family name (Optional)' }); const webIdInput = screen.getByPlaceholderText('WebId'); @@ -87,6 +91,10 @@ describe('add contact', () => { {}} showAddContactModal addContact={mockAdd} /> ); + await userEvent.click(testGetByRole(screen.getByTestId('select-oidc'), 'combobox')); + + await userEvent.click(await screen.findByRole('option', { name: 'Other' })); + const givenName = screen.getByRole('textbox', { name: 'First/given name (Optional)' }); const familyName = screen.getByRole('textbox', { name: 'Last/family name (Optional)' }); const webIdInput = screen.getByPlaceholderText('WebId'); From 077756394a32d60c0b2dcde8d4472838a9ca3970 Mon Sep 17 00:00:00 2001 From: Tim Standen <37914436+timbot1789@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:38:57 -0700 Subject: [PATCH 024/263] Fix sharing of one document (#601) --- src/components/Documents/DocumentTable.jsx | 2 +- .../Modals/SetAclPermissionsModal.jsx | 2 +- src/utils/network/session-core.js | 20 +++++++------------ test/utils/session-core.test.js | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/components/Documents/DocumentTable.jsx b/src/components/Documents/DocumentTable.jsx index f5d2c33fa..fbbb57fba 100644 --- a/src/components/Documents/DocumentTable.jsx +++ b/src/components/Documents/DocumentTable.jsx @@ -154,7 +154,7 @@ const DocumentTable = ({ handleAclPermissionsModal, handleSelectDeleteDoc }) => getActions: (data) => [ } - onClick={() => handleAclPermissionsModal('documents', data.name, data.type)} + onClick={() => handleAclPermissionsModal('document', data.row.id, data.row.type)} label="Share" /> ] diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index 8c216ac9d..b85a2f97a 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -75,7 +75,7 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { case 'document': await setDocAclPermission( session, - dataset.docType, + dataset.docName, permissions, podUrl, webIdToSetPermsTo diff --git a/src/utils/network/session-core.js b/src/utils/network/session-core.js index 0bb864fc2..d66d09655 100644 --- a/src/utils/network/session-core.js +++ b/src/utils/network/session-core.js @@ -1,4 +1,4 @@ -import { getFile } from '@inrupt/solid-client'; +import { getFile, universalAccess } from '@inrupt/solid-client'; import dayjs from 'dayjs'; import { v4 as uuidv4 } from 'uuid'; import { @@ -32,24 +32,18 @@ import { * @memberof utils * @function setDocAclPermission * @param {Session} session - Solid's Session Object {@link Session} - * @param {string} docType - Type of document + * @param {string} docName - Name of document to share * @param {Access} permissions - The Access object for setting ACL in Solid * @param {URL} podUrl - URL of the user's Pod - * @param {string} webIdToSetPermsTo - URL of the other user's Pod to give/revoke permissions OR empty string + * @param {string} webId - The webId to share the document with * @returns {Promise} Promise - Sets permission for otherPodUsername for given * document type, if exists, or null */ -export const setDocAclPermission = async ( - session, - docType, - permissions, - podUrl, - webIdToSetPermsTo -) => { +export const setDocAclPermission = async (session, docName, permissions, podUrl, webId) => { const containerUrl = `${podUrl}PASS/Documents/`; - const documentUrl = `${containerUrl}${docType.replace("'", '').replace(' ', '_')}/`; + const documentUrl = `${containerUrl}${docName.replace("'", '').replace(' ', '_')}`; - await setDocAclForUser(session, documentUrl, 'update', webIdToSetPermsTo, permissions); + await universalAccess.setAgentAccess(documentUrl, webId, permissions, { fetch: session.fetch }); }; /** @@ -72,7 +66,7 @@ export const setDocContainerAclPermission = async ( ) => { const containerUrl = `${podUrl}PASS/Documents/`; - await setDocAclForUser(session, containerUrl, 'update', webIdToSetPermsTo, permissions); + await setDocAclForUser(session, containerUrl, '', webIdToSetPermsTo, permissions); }; /* diff --git a/test/utils/session-core.test.js b/test/utils/session-core.test.js index 88540ba0c..6dbe04ca3 100644 --- a/test/utils/session-core.test.js +++ b/test/utils/session-core.test.js @@ -39,7 +39,7 @@ describe('setDocContainerAclPermission', () => { expect(sessionHelpers.setDocAclForUser).toBeCalledWith( session, expectedContainerUrl, - 'update', + '', expectedWebId, permissions ); From ba9f7a8164291ae91f3479ae81b067319728ab5a Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:43:25 -0700 Subject: [PATCH 025/263] Mocked ENV variable --- src/components/Modals/AddContactModal.jsx | 2 +- test/components/Modals/AddContactModal.test.jsx | 12 ++++++++++++ test/helpers/setup-vitest.js | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 959bb9bb7..d8ea3bc33 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -61,7 +61,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const [oidcProviders] = useState([...ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', '), 'Other']); - const [Oidc, setOIDC] = React.useState(''); + const [Oidc, setOIDC] = useState(''); const oidcForm = { 'http://localhost:3000/': 'http://localhost:3000/user/profile/card#me', diff --git a/test/components/Modals/AddContactModal.test.jsx b/test/components/Modals/AddContactModal.test.jsx index 80ed0d40d..8dbfdee42 100644 --- a/test/components/Modals/AddContactModal.test.jsx +++ b/test/components/Modals/AddContactModal.test.jsx @@ -6,6 +6,18 @@ import { AddContactModal } from '@components/Modals'; import * as solidClient from '@inrupt/solid-client'; import createMatchMedia from '../../helpers/createMatchMedia'; +vi.mock('../../../src/constants/', async () => { + const actual = await vi.importActual('../../../src/constants/'); + return { + ...actual, + ENV: { + VITE_SOLID_IDENTITY_PROVIDER: 'https://www.testurl.com/', + VITE_SUGGESTED_OIDC_OPTIONS: + 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' + } + }; +}); + const MockAddContactModal = () => ; it('renders button container flex-direction row default', () => { diff --git a/test/helpers/setup-vitest.js b/test/helpers/setup-vitest.js index bd36aa475..8c463b478 100644 --- a/test/helpers/setup-vitest.js +++ b/test/helpers/setup-vitest.js @@ -2,6 +2,9 @@ import { afterEach } from 'vitest'; import createMatchMedia from './createMatchMedia'; +// process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net', +// process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' + afterEach(() => { window.matchMedia = createMatchMedia(1200); }); From 7580159557d09ad2016268cc97fe5b9b20638083 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:50:38 -0700 Subject: [PATCH 026/263] Setup ENV variables in setupFile --- test/components/Modals/AddContactModal.test.jsx | 12 ------------ test/helpers/setup-vitest.js | 4 ++-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/test/components/Modals/AddContactModal.test.jsx b/test/components/Modals/AddContactModal.test.jsx index 8dbfdee42..80ed0d40d 100644 --- a/test/components/Modals/AddContactModal.test.jsx +++ b/test/components/Modals/AddContactModal.test.jsx @@ -6,18 +6,6 @@ import { AddContactModal } from '@components/Modals'; import * as solidClient from '@inrupt/solid-client'; import createMatchMedia from '../../helpers/createMatchMedia'; -vi.mock('../../../src/constants/', async () => { - const actual = await vi.importActual('../../../src/constants/'); - return { - ...actual, - ENV: { - VITE_SOLID_IDENTITY_PROVIDER: 'https://www.testurl.com/', - VITE_SUGGESTED_OIDC_OPTIONS: - 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' - } - }; -}); - const MockAddContactModal = () => ; it('renders button container flex-direction row default', () => { diff --git a/test/helpers/setup-vitest.js b/test/helpers/setup-vitest.js index 8c463b478..a952778cb 100644 --- a/test/helpers/setup-vitest.js +++ b/test/helpers/setup-vitest.js @@ -2,8 +2,8 @@ import { afterEach } from 'vitest'; import createMatchMedia from './createMatchMedia'; -// process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net', -// process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' +process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net', +process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' afterEach(() => { window.matchMedia = createMatchMedia(1200); From 5be7cf40530ca9c84bc2cbc00237122bf287a716 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:58:18 -0700 Subject: [PATCH 027/263] Fixed prettier errors --- test/helpers/setup-vitest.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/helpers/setup-vitest.js b/test/helpers/setup-vitest.js index a952778cb..4c74cbc6c 100644 --- a/test/helpers/setup-vitest.js +++ b/test/helpers/setup-vitest.js @@ -2,8 +2,9 @@ import { afterEach } from 'vitest'; import createMatchMedia from './createMatchMedia'; -process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net', -process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/' +process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net'; +process.env.VITE_SUGGESTED_OIDC_OPTIONS = + 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/'; afterEach(() => { window.matchMedia = createMatchMedia(1200); From 3b4c46e955b45a10e58a040f1bfb56919e22cebb Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sat, 23 Mar 2024 10:33:23 -0700 Subject: [PATCH 028/263] Moved the webID to the the ENV file --- env.template | 1 + src/components/Modals/AddContactModal.jsx | 15 +++------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/env.template b/env.template index c8877277f..bbf2be67b 100644 --- a/env.template +++ b/env.template @@ -1,4 +1,5 @@ VITE_SOLID_IDENTITY_PROVIDER="http://localhost:3000/" VITE_SOLID_POD_SERVER="http://localhost:3000/" VITE_SUGGESTED_OIDC_OPTIONS="http://localhost:3000/, https://opencommons.net/, https://solidcommunity.net/, https://login.inrupt.com/, https://inrupt.net/" +VITE_OIDC_WEBIDS = '{"http://localhost:3000/": "http://localhost:3000/user/profile/card#me", "https://opencommons.net/": "http://opencommons.net/user/profile/card#me", "https://solidcommunity.net/": "https://user.solidcommunity.net/profile/card#me", "https://login.inrupt.com/": "https://id.inrupt.com/user", "https://inrupt.net/": "https://id.inrupt.com/user"}' VITE_CLIENT_ID_DOC="http://localhost:3000/clientAppId.json" diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index d8ea3bc33..fd7b41383 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -21,12 +21,11 @@ import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; // Custom Hook Imports import useNotification from '@hooks/useNotification'; -// Component Imports +// Constant Imports import { ENV } from '@constants'; +// Component Imports import { FormSection } from '../Form'; -// Constant Imports - // @memberof Modals // @name renderWebId // @param {string} username - Username to convert into a webId @@ -63,14 +62,6 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod const [oidcProviders] = useState([...ENV.VITE_SUGGESTED_OIDC_OPTIONS.split(', '), 'Other']); const [Oidc, setOIDC] = useState(''); - const oidcForm = { - 'http://localhost:3000/': 'http://localhost:3000/user/profile/card#me', - 'https://opencommons.net/': 'http://opencommons.net/user/profile/card#me', - 'https://solidcommunity.net/': 'https://user.solidcommunity.net/profile/card#me.', - 'https://login.inrupt.com/': 'https://id.inrupt.com/user', - 'https://inrupt.net/': 'https://id.inrupt.com/user' - }; - const clearInputFields = () => { setUserGivenName(''); setUserFamilyName(''); @@ -105,7 +96,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod }; } else { userObject = { - webId: oidcForm[Oidc].replace('user', userName.trim()).trim(), + webId: JSON.parse(ENV.VITE_OIDC_WEBIDS)[Oidc].replace('user', userName.trim()).trim(), ...(addUserGivenName.value && { givenName: addUserGivenName.value.trim() }), ...(addUserFamilyName.value && { familyName: addUserFamilyName.value.trim() }) }; From 418bc1711fa147f6c930f1a5e14b9af200f4913a Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sat, 23 Mar 2024 10:44:09 -0700 Subject: [PATCH 029/263] Added ENV WebID variables to tests --- test/helpers/setup-vitest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/helpers/setup-vitest.js b/test/helpers/setup-vitest.js index 4c74cbc6c..1cb19b8fc 100644 --- a/test/helpers/setup-vitest.js +++ b/test/helpers/setup-vitest.js @@ -5,6 +5,7 @@ import createMatchMedia from './createMatchMedia'; process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net'; process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/'; +process.env.VITE_OIDC_WEBIDS = '{"http://testurl_1.com/": "http://testurl_1.com/user/profile/card#me", "http://testurl_2.com/": "http://testurl_2.com/user/profile/card#me", "http://testurl_3.com/": "http://testurl_3.com/user/profile/card#me"}' afterEach(() => { window.matchMedia = createMatchMedia(1200); From 9df38585a40071411d64ad326170edd645a61c25 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sat, 23 Mar 2024 10:46:08 -0700 Subject: [PATCH 030/263] Ran Prettier for formatting --- test/helpers/setup-vitest.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/helpers/setup-vitest.js b/test/helpers/setup-vitest.js index 1cb19b8fc..5e8c3f3ca 100644 --- a/test/helpers/setup-vitest.js +++ b/test/helpers/setup-vitest.js @@ -5,7 +5,8 @@ import createMatchMedia from './createMatchMedia'; process.env.VITE_SOLID_IDENTITY_PROVIDER = 'https://solidcommunity.net'; process.env.VITE_SUGGESTED_OIDC_OPTIONS = 'http://testurl_1.com/, http://testurl_2.com/, http://testurl_3.com/'; -process.env.VITE_OIDC_WEBIDS = '{"http://testurl_1.com/": "http://testurl_1.com/user/profile/card#me", "http://testurl_2.com/": "http://testurl_2.com/user/profile/card#me", "http://testurl_3.com/": "http://testurl_3.com/user/profile/card#me"}' +process.env.VITE_OIDC_WEBIDS = + '{"http://testurl_1.com/": "http://testurl_1.com/user/profile/card#me", "http://testurl_2.com/": "http://testurl_2.com/user/profile/card#me", "http://testurl_3.com/": "http://testurl_3.com/user/profile/card#me"}'; afterEach(() => { window.matchMedia = createMatchMedia(1200); From 6f3dc5381e5ca74bcc4e5c73297392407b6c31a3 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Sun, 24 Mar 2024 11:28:25 -0700 Subject: [PATCH 031/263] Added tooltips to OIDC, Username and Custom WebID --- src/components/Modals/AddContactModal.jsx | 121 ++++++++++++---------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index fd7b41383..d191c00dd 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -19,6 +19,7 @@ import MenuItem from '@mui/material/MenuItem'; import InputLabel from '@mui/material/InputLabel'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; +import Tooltip from '@mui/material/Tooltip'; // Custom Hook Imports import useNotification from '@hooks/useNotification'; // Constant Imports @@ -151,67 +152,77 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod onChange={(e) => setUserFamilyName(e.target.value)} fullWidth /> - - OIDC Provider - - + + + OIDC Provider + + + {!customWebID && ( - + + + setUserName(e.target.value)} + fullWidth + autoFocus + /> + + + )} + {customWebID && ( + setUserName(e.target.value)} + id="add-webId" + name="addWebId" + placeholder="WebId" + autoComplete="webid" + value={webId} + type="text" + onChange={(e) => { + setWebId(e.target.value); + }} + error={invalidWebId} + label={invalidWebId ? 'Error' : ''} + // helperText for invalidWebId === false is ' ' and not '' is to + // prevent the field from stretching when helperText disappears + helperText={invalidWebId ? 'Invalid WebId.' : ' '} fullWidth - autoFocus + InputProps={{ + endAdornment: ( + + + + + + ) + }} /> - - )} - {customWebID && ( - { - setWebId(e.target.value); - }} - error={invalidWebId} - label={invalidWebId ? 'Error' : ''} - // helperText for invalidWebId === false is ' ' and not '' is to - // prevent the field from stretching when helperText disappears - helperText={invalidWebId ? 'Invalid WebId.' : ' '} - fullWidth - InputProps={{ - endAdornment: ( - - - - - - ) - }} - /> + )} Date: Wed, 27 Mar 2024 19:31:34 -0700 Subject: [PATCH 032/263] remove workflow and add projects to issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 3 ++- .github/ISSUE_TEMPLATE/enhancement_request.md | 3 ++- .github/ISSUE_TEMPLATE/feature_request.md | 3 ++- .github/workflows/add_project_to_issue.yml | 15 --------------- 4 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 .github/workflows/add_project_to_issue.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e44c3883f..cb79da403 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,6 +3,7 @@ name: Bug report about: Create a bug report title: '[Bug Report] - Your Title Here' labels: 'bug' +projects: 'PASS' assignees: '' --- @@ -35,4 +36,4 @@ Steps to reproduce the behavior: If you have a suggestion for how to fix the bug, please provide details here. ### Additional context: -Add any other context about the problem here. \ No newline at end of file +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.md b/.github/ISSUE_TEMPLATE/enhancement_request.md index 09331a9ad..f4326a789 100644 --- a/.github/ISSUE_TEMPLATE/enhancement_request.md +++ b/.github/ISSUE_TEMPLATE/enhancement_request.md @@ -3,6 +3,7 @@ name: Enhancement request about: Suggest an enhancement for this project title: '[Enhancement] - Your Title Here' labels: enhancement +projects: 'PASS' assignees: '' --- @@ -31,4 +32,4 @@ Discuss any potential drawbacks or negative impacts this enhancement might have, Mention any alternative solutions or enhancements you've considered. Why were they not chosen or why are they less desirable than your proposal? ### Additional Context: -Add any other context or screenshots about the enhancement request here. \ No newline at end of file +Add any other context or screenshots about the enhancement request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 13a8dda23..6dea5bcd1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -3,6 +3,7 @@ name: Feature request about: Suggest an idea for this project title: '[Feature Request] - Your Title Here ' labels: 'new feature' +projects: 'PASS' assignees: '' --- @@ -20,4 +21,4 @@ If you have a specific solution in mind, outline it here. Include as many detail A clear and concise description of any alternative solutions or features you've considered and why they could or could not work. ### Additional Context: -Add any other context or screenshots about the feature request here. If you have mock-ups, prototypes, or any visual aids that could help illustrate the feature, please include them. \ No newline at end of file +Add any other context or screenshots about the feature request here. If you have mock-ups, prototypes, or any visual aids that could help illustrate the feature, please include them. diff --git a/.github/workflows/add_project_to_issue.yml b/.github/workflows/add_project_to_issue.yml deleted file mode 100644 index 5f633511a..000000000 --- a/.github/workflows/add_project_to_issue.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Add Project to New Issue -on: - issues: - types: - - opened -jobs: - add-to-project: - name: Add issue to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v0.5.0 - with: - project-url: https://github.com/orgs/codeforpdx/projects/3 - github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} - label-operator: OR From f917083598be7cf637ebaf4c1c074ce50da59289 Mon Sep 17 00:00:00 2001 From: Joshua Cornett Date: Tue, 2 Apr 2024 01:04:38 -0700 Subject: [PATCH 033/263] feat(Share Document modal): Add contact list dropdown for Pod URL --- .../Modals/SetAclPermissionsModal.jsx | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index b85a2f97a..83805344c 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -1,7 +1,7 @@ // React Imports import React, { useContext, useState } from 'react'; // Custom Hook Imports -import { useSession } from '@hooks'; +import { useSession, useContactsList } from '@hooks'; // Material UI Imports import Button from '@mui/material/Button'; import ClearIcon from '@mui/icons-material/Clear'; @@ -12,6 +12,7 @@ import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; import ShareIcon from '@mui/icons-material/Share'; import TextField from '@mui/material/TextField'; +import Autocomplete from '@mui/material/Autocomplete'; // Utility Imports import { setDocAclPermission, setDocContainerAclPermission } from '@utils'; // Context Imports @@ -46,6 +47,15 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { }); const [processing, setProcessing] = useState(false); + const { data } = useContactsList(); + const contactListOptions = data?.map((contact) => ({ + label: `${contact.person} ${contact.podUrl}`, + id: contact.podUrl + })); + const shareeName = data?.filter( + (contact) => permissionState.podUrlToSetPermissionsTo === contact.podUrl + )[0]; + const clearInputFields = () => { setPermissionState({ podUrlToSetPermissionsTo: '', @@ -125,28 +135,33 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => {
- - - setPermissionState({ - ...permissionState, - podUrlToSetPermissionsTo: e.target.value - }) - } - placeholder={permissionState.podUrlToSetPermissionsTo} - label="Enter podURL" - required - error={permissionState.podUrlToSetPermissionsTo === podUrl} - helperText={ - permissionState.podUrlToSetPermissionsTo === podUrl - ? 'Cannot share to your own pod.'.toUpperCase() - : '' - } - /> - + { + setPermissionState({ + ...permissionState, + podUrlToSetPermissionsTo: newValue.id ?? newValue + }); + }} + placeholder={permissionState.podUrlToSetPermissionsTo} + error={permissionState.podUrlToSetPermissionsTo === podUrl} + helperText={ + permissionState.podUrlToSetPermissionsTo === podUrl + ? 'Cannot share to your own pod.'.toUpperCase() + : '' + } + renderInput={(params) => } + />
-
- - + Clear + + + + + - + ); }; diff --git a/test/components/CivicProfileForms/BasicInfo.test.jsx b/test/components/CivicProfileForms/BasicInfo.test.jsx index 9b8a40a1d..4c6058a7e 100644 --- a/test/components/CivicProfileForms/BasicInfo.test.jsx +++ b/test/components/CivicProfileForms/BasicInfo.test.jsx @@ -26,10 +26,10 @@ describe('Basic info form', () => { const user = userEvent.setup(); const mockAdd = vi.fn(); const basicInfoProfile = { - firstName: 'John', - lastName: 'Doe', - dateOfBirth: '1980-12-15', - gender: 'Male' + legalFirstName: 'Jane', + legalLastName: 'Doe', + legalDOB: '1980-12-15', + legalGender: 0 }; useCivicProfile.mockReturnValue({ add: mockAdd, isSuccess: true }); const { getByRole } = render(); @@ -37,13 +37,13 @@ describe('Basic info form', () => { const lastNameField = getByRole('textbox', { name: 'Legal last name' }); const dateOfBirthField = getByRole('textbox', { name: 'Choose date' }); const genderField = getByRole('combobox', { name: 'Gender' }); - const clearButton = getByRole('button', { name: 'Clear button' }); + // const clearButton = getByRole('button', { name: 'Clear button' }); const submitButton = getByRole('button', { name: 'Submit button' }); - await user.type(firstNameField, basicInfoProfile.firstName); - await user.type(lastNameField, basicInfoProfile.lastName); - await userEvent.type(dateOfBirthField, basicInfoProfile.dateOfBirth); - await userEvent.type(genderField, `${basicInfoProfile.gender}{enter}`); - await user.click(clearButton); + await user.type(firstNameField, basicInfoProfile.legalFirstName); + await user.type(lastNameField, basicInfoProfile.legalLastName); + await user.type(dateOfBirthField, basicInfoProfile.legalDOB); + await user.type(genderField, `${basicInfoProfile.legalGender}{enter}`); + // await user.click(clearButton); await user.click(submitButton); expect(mockAdd).toBeCalledWith(basicInfoProfile); }); From d4b52facbd171d0a39cd6ec37f8134b08b381065 Mon Sep 17 00:00:00 2001 From: Joshua Cornett Date: Tue, 2 Apr 2024 22:25:06 -0700 Subject: [PATCH 036/263] style(FormSection > SetAclPermissionsModal): Adjust header and field spacing --- src/components/Form/FormSection.jsx | 3 ++- src/components/Modals/SetAclPermissionsModal.jsx | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Form/FormSection.jsx b/src/components/Form/FormSection.jsx index be2495bba..38f58c44b 100644 --- a/src/components/Form/FormSection.jsx +++ b/src/components/Form/FormSection.jsx @@ -27,7 +27,8 @@ const FormSection = ({ title, headingId, children }) => ( alignItems: 'center', mx: '3px', padding: '16px', - minWidth: '50%' + minWidth: '50%', + maxWidth: '75vdw' }} > diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index e0f0f5c25..eb06c0a28 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -123,8 +123,8 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { dataset.modalType === 'container' ? 'Share All Documents' : `Share ${dataset.docName}` } > -
- + + Select One { fullWidth required autoFocus - value={shareeName?.person ?? permissionState.webIdToSetPermsTo} + value={shareName?.person ?? permissionState.webIdToSetPermsTo} disablePortal autoSelect options={contactListOptions} From 8fc2e2cd54d0585b834202035917bfd1483c2ec4 Mon Sep 17 00:00:00 2001 From: Joshua Cornett Date: Tue, 9 Apr 2024 13:37:34 -0700 Subject: [PATCH 039/263] refactor(document sharing modal): removed moot reference to pod URL, used ubiquitous event placeholder, changed webID placeholder to meaningful text --- src/components/Modals/SetAclPermissionsModal.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index 25167b0b2..c7eb20450 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -154,14 +154,14 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { disablePortal autoSelect options={contactListOptions} - onChange={(event, newValue) => { + onChange={(_, newValue) => { setPermissionState({ ...permissionState, webIdToSetPermsTo: newValue.id ?? newValue }); }} - placeholder={permissionState.podUrlToSetPermissionsTo} - error={permissionState.podUrlToSetPermissionsTo === podUrl} + placeholder="WebID to share with" + error={permissionState.webIdToSetPermsTo === webId} helperText={ permissionState.webIdToSetPermsTo === webId ? 'Cannot share to your own pod.'.toUpperCase() From 37e908655ac49713abcca6fe721fb5c5b9e82882 Mon Sep 17 00:00:00 2001 From: Russell Fraze <81979567+russfraze@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:29:22 -0700 Subject: [PATCH 040/263] 607 enhancement update the profile card (#612) * single card * change container to box * feedback changes * fix test on incon button --- src/components/Profile/ProfileComponent.jsx | 23 +++++++++------- .../Profile/ProfileEditButtonGroup.jsx | 18 +++++-------- src/components/Profile/ProfileImageField.jsx | 1 - src/components/Profile/ProfileInputField.jsx | 4 ++- src/pages/Profile.jsx | 26 +++++++------------ 5 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/components/Profile/ProfileComponent.jsx b/src/components/Profile/ProfileComponent.jsx index c587dd54c..d4368515f 100644 --- a/src/components/Profile/ProfileComponent.jsx +++ b/src/components/Profile/ProfileComponent.jsx @@ -13,9 +13,9 @@ import { useTheme } from '@mui/material/styles'; // Context Imports import { SignedInUserContext } from '@contexts'; // Component Inputs -import ProfileImageField from './ProfileImageField'; import ProfileInputField from './ProfileInputField'; import ProfileEditButtonGroup from './ProfileEditButtonGroup'; +import ProfileImageField from './ProfileImageField'; /** * The UserProfile Component is a component that renders the user's profile on @@ -86,7 +86,9 @@ const ProfileComponent = ({ contactProfile, webId }) => { display: 'flex', flexDirection: isSmallScreen ? 'column' : 'row', gap: '15px', - padding: '10px' + padding: '10px', + boxShadow: '0 6px 20px rgba(0, 0, 0, 0.25)', + borderRadius: '10px' }} > @@ -95,9 +97,8 @@ const ProfileComponent = ({ contactProfile, webId }) => { style={{ display: 'flex', flexDirection: 'column', - boxShadow: '0 0 3px 0 black', justifyContent: 'space-between', - padding: '20px' + padding: '10px' }} > { gap: '10px' }} > + {!contactProfile && ( + + )} { /> {!contactProfile && ( - - + Your Invite Link diff --git a/src/components/Profile/ProfileEditButtonGroup.jsx b/src/components/Profile/ProfileEditButtonGroup.jsx index dfd309bf9..175c0ba68 100644 --- a/src/components/Profile/ProfileEditButtonGroup.jsx +++ b/src/components/Profile/ProfileEditButtonGroup.jsx @@ -3,9 +3,10 @@ import React from 'react'; // Material UI Imports import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; +import IconButton from '@mui/material/IconButton'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; -import EditIcon from '@mui/icons-material/Edit'; +import EditNote from '@mui/icons-material/EditNote'; /** * The ProfileEditButtonGroup Component is a component that consist of the profile @@ -27,7 +28,7 @@ const ProfileEditButtonGroup = ({ edit, handleCancelEdit, handleEditInput }) => sx={{ display: 'flex', gap: '10px', - marginTop: '10px' + alignSelf: 'end' }} > {edit ? ( @@ -47,16 +48,9 @@ const ProfileEditButtonGroup = ({ edit, handleCancelEdit, handleEditInput }) => ) : ( - + + + )} ); diff --git a/src/components/Profile/ProfileImageField.jsx b/src/components/Profile/ProfileImageField.jsx index 032a1cd0a..8f417e2a2 100644 --- a/src/components/Profile/ProfileImageField.jsx +++ b/src/components/Profile/ProfileImageField.jsx @@ -77,7 +77,6 @@ const ProfileImageField = ({ loadProfileData, contactProfile }) => { flexDirection: 'column', justifyContent: 'center', alignItems: 'center', - boxShadow: '0 0 3px 0 black', padding: '20px', gap: '10px' }} diff --git a/src/components/Profile/ProfileInputField.jsx b/src/components/Profile/ProfileInputField.jsx index a5c792943..cf290a377 100644 --- a/src/components/Profile/ProfileInputField.jsx +++ b/src/components/Profile/ProfileInputField.jsx @@ -21,11 +21,13 @@ import InputLabel from '@mui/material/InputLabel'; * @returns {React.JSX.Element} React component for NewMessage */ const ProfileInputField = ({ inputName, inputValue, setInputValue, edit, endAdornment }) => ( - + {inputName}: + { width: '100%' }} > - - Profile Information + + My Profile - - {!contact && ( @@ -161,24 +156,23 @@ const Profile = () => { variant="contained" color="primary" size="small" - startIcon={} onClick={() => handleAclPermissionsModal('container')} - sx={{ width: isSmallScreen ? '250px' : 'default' }} + sx={{ width: isSmallScreen ? '165px' : '200px' }} > - Share Documents Folder + Share Documents )} - + + Date: Wed, 17 Apr 2024 14:50:45 -0700 Subject: [PATCH 041/263] refetch is storedDocument is null --- src/components/CivicProfileForms/HousingInfo.jsx | 11 ++++++++--- src/components/Modals/SetAclPermissionsModal.jsx | 4 ++-- src/hooks/useRdfCollection.js | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 2ad49d964..1212ae4e4 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -14,7 +14,7 @@ import { useCivicProfile } from '@hooks'; * @returns {React.JSX.Element} The HousingInfo Component */ const HousingInfo = () => { - const { data, add, isSuccess } = useCivicProfile(); + const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); const [formData, setFormData] = useState({ lastPermanentStreet: '', lastPermanentCity: '', @@ -27,16 +27,21 @@ const HousingInfo = () => { setFormData((prevFormData) => ({ ...prevFormData, ...data })); } }, [isSuccess, data]); - + useEffect(() => { + if (!storedDataset) { + refetch(); + } + }, [storedDataset]); const handleChange = (event) => { const { name, value } = event.target; setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); }; const handleSubmit = (e) => { e.preventDefault(); - if (!isSuccess) { + if (!isSuccess || !storedDataset) { return; } + add(formData); }; diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index c7eb20450..418392d2e 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -154,10 +154,10 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { disablePortal autoSelect options={contactListOptions} - onChange={(_, newValue) => { + onChange={(_, value) => { setPermissionState({ ...permissionState, - webIdToSetPermsTo: newValue.id ?? newValue + webIdToSetPermsTo: value.id ?? value }); }} placeholder="WebID to share with" diff --git a/src/hooks/useRdfCollection.js b/src/hooks/useRdfCollection.js index cd707b334..ceaf205e8 100644 --- a/src/hooks/useRdfCollection.js +++ b/src/hooks/useRdfCollection.js @@ -70,6 +70,7 @@ const useRdfCollection = (parse, serialize, fileUrl, fetchData) => { const addMutation = useMutation({ mutationFn: async (item) => { if (!data) await fetchDocument(); + // HERE const thing = serialize(item); const newDataset = setThing(storedDataset, thing); const savedDataset = await saveData(newDataset); From a0af44e0e9228bf4f865187f8fce3fb52417f7f3 Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Wed, 17 Apr 2024 14:55:32 -0700 Subject: [PATCH 042/263] undo setAcl changes --- src/components/Modals/SetAclPermissionsModal.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index 418392d2e..c7eb20450 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -154,10 +154,10 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { disablePortal autoSelect options={contactListOptions} - onChange={(_, value) => { + onChange={(_, newValue) => { setPermissionState({ ...permissionState, - webIdToSetPermsTo: value.id ?? value + webIdToSetPermsTo: newValue.id ?? newValue }); }} placeholder="WebID to share with" From 0c2a13a91523131f33f24daf4c30322f4a4a3dfb Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Thu, 18 Apr 2024 10:19:45 -0700 Subject: [PATCH 043/263] update and add tests for bugfix --- .../CivicProfileForms/HousingInfo.test.jsx | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/components/CivicProfileForms/HousingInfo.test.jsx b/test/components/CivicProfileForms/HousingInfo.test.jsx index 6bbf85adb..c11af93f0 100644 --- a/test/components/CivicProfileForms/HousingInfo.test.jsx +++ b/test/components/CivicProfileForms/HousingInfo.test.jsx @@ -16,7 +16,7 @@ vi.mock('@hooks', async () => { describe('Housing info form', () => { it('renders', () => { - useCivicProfile.mockReturnValue({ data: {}, isSuccess: true }); + useCivicProfile.mockReturnValue({ data: {}, isSuccess: true, refetch: vi.fn() }); const { getByRole } = render(); const cityField = getByRole('textbox', { name: 'City:' }); expect(cityField).not.toBeNull(); @@ -31,7 +31,12 @@ describe('Housing info form', () => { lastPermanentState: 'Oregon', lastPermanentZIP: '97205' }; - useCivicProfile.mockReturnValue({ add: mockAdd, isSuccess: true }); + useCivicProfile.mockReturnValue({ + add: mockAdd, + isSuccess: true, + storedDataset: {}, + refetch: vi.fn() + }); const { getByRole } = render(); const cityField = getByRole('textbox', { name: 'City:' }); const streetField = getByRole('textbox', { name: 'Street:' }); @@ -45,4 +50,32 @@ describe('Housing info form', () => { await user.click(submitButton); expect(mockAdd).toBeCalledWith(address); }); + it('does not submit when storedDataset is null', async () => { + const user = userEvent.setup(); + const mockAdd = vi.fn(); + const address = { + lastPermanentCity: 'Portland', + lastPermanentStreet: '20th ave', + lastPermanentState: 'Oregon', + lastPermanentZIP: '97205' + }; + useCivicProfile.mockReturnValue({ + add: mockAdd, + isSuccess: true, + storedDataset: null, + refetch: vi.fn() + }); + const { getByRole } = render(); + const cityField = getByRole('textbox', { name: 'City:' }); + const streetField = getByRole('textbox', { name: 'Street:' }); + const stateField = getByRole('textbox', { name: 'State:' }); + const zipField = getByRole('textbox', { name: 'ZIP Code:' }); + const submitButton = getByRole('button'); + await user.type(cityField, address.lastPermanentCity); + await user.type(streetField, address.lastPermanentStreet); + await user.type(stateField, address.lastPermanentState); + await user.type(zipField, address.lastPermanentZIP); + await user.click(submitButton); + expect(mockAdd).not.toBeCalled(); + }); }); From ce1d89191d037f885ec2b4cd7c06f2628b562831 Mon Sep 17 00:00:00 2001 From: Jacob Gifford <105343665+JaeGif@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:13:04 -0700 Subject: [PATCH 044/263] Update useRdfCollection.js Remove comment --- src/hooks/useRdfCollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useRdfCollection.js b/src/hooks/useRdfCollection.js index ceaf205e8..ca024e888 100644 --- a/src/hooks/useRdfCollection.js +++ b/src/hooks/useRdfCollection.js @@ -70,7 +70,7 @@ const useRdfCollection = (parse, serialize, fileUrl, fetchData) => { const addMutation = useMutation({ mutationFn: async (item) => { if (!data) await fetchDocument(); - // HERE + const thing = serialize(item); const newDataset = setThing(storedDataset, thing); const savedDataset = await saveData(newDataset); From 362d96195d6b2e82c1408691c34c815f1315c017 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 18 Apr 2024 15:26:48 -0700 Subject: [PATCH 045/263] Adjust form input responsiveness --- src/components/CivicProfileForms/BasicInfo.jsx | 12 ++++++------ src/components/CivicProfileForms/HousingInfo.jsx | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index e53e83812..573c78612 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -71,7 +71,7 @@ const BasicInfo = () => { - + { autoFocus /> - + { fullWidth /> - + { YYYY-MM-DD - + Gender - + - + + {hasWebCam ? ( ) : ( From 63725e16443554668ed612bfd14a5ed57109ab62 Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Sat, 27 Apr 2024 11:23:06 -0700 Subject: [PATCH 058/263] begins contacts theme --- src/components/Modals/UploadDocumentModal.jsx | 10 ++-- .../Notification/EmptyListNotification.jsx | 2 +- src/pages/Contacts.jsx | 50 +++++++++++++++---- src/theme.js | 1 + 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/components/Modals/UploadDocumentModal.jsx b/src/components/Modals/UploadDocumentModal.jsx index d18289531..db2a57a71 100644 --- a/src/components/Modals/UploadDocumentModal.jsx +++ b/src/components/Modals/UploadDocumentModal.jsx @@ -17,19 +17,19 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; -import Slide from '@mui/material/Slide'; -// Context Imports +/* import Slide from '@mui/material/Slide'; + */ // Context Imports import { DocumentListContext } from '@contexts'; // Component Imports import { DocumentSelection, FormSection } from '../Form'; import UploadButtonGroup from './UploadButtonGroup'; import useNotification from '../../hooks/useNotification'; import UploadDocumentConfirmationModal from './UploadDocumentConfirmationModal'; - +/* const Transition = React.forwardRef((props, ref) => { ; }); - + */ /** * UploadDocumentModal Component - Component that generates the form for uploading * a specific document type to a user's Solid Pod via Solid Session @@ -133,7 +133,6 @@ const UploadDocumentModal = ({ showModal, setShowModal }) => { return ( { onConfirm={confirmationModalType === 'add' ? handleDocAdd : handleDocReplace} uploadType={confirmationModalType} /> + km { > - + {str1} {type !== 'messages' ? ( <> diff --git a/src/pages/Contacts.jsx b/src/pages/Contacts.jsx index 72cd816a0..d098d780b 100644 --- a/src/pages/Contacts.jsx +++ b/src/pages/Contacts.jsx @@ -1,11 +1,12 @@ // React Imports import React, { useState } from 'react'; // Material UI Imports -import AddIcon from '@mui/icons-material/Add'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Container from '@mui/material/Container'; import Typography from '@mui/material/Typography'; +import { FormControl, Select, MenuItem } from '@mui/material'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; // Component Imports import { useContactsList, useNotification } from '@hooks'; import { AddContactModal, ConfirmationModal } from '@components/Modals'; @@ -19,6 +20,7 @@ import { LoadingAnimation, EmptyListNotification } from '@components/Notificatio * @name Contacts * @returns {React.JSX.Component} - the Contacts Page */ + const Contacts = () => { localStorage.setItem('restorePath', '/contacts'); const [showAddContactModal, setShowAddContactModal] = useState(false); @@ -34,6 +36,7 @@ const Contacts = () => { delete: deleteContact } = useContactsList(); const { addNotification } = useNotification(); + const [fieldType, setFieldType] = useState('First Name'); const getContactDisplayName = (contact) => { if (!contact) { @@ -76,15 +79,42 @@ const Contacts = () => { }} > - + + + + + + {data.length > 0 ? ( Date: Sun, 28 Apr 2024 15:39:28 -0700 Subject: [PATCH 059/263] new colors add to theme --- src/components/Footer/Footer.jsx | 2 +- src/components/NavBar/NavBarSkipLink.jsx | 4 +- src/theme.js | 47 ++---------------------- 3 files changed, 6 insertions(+), 47 deletions(-) diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index 33914f901..ba39df488 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -44,7 +44,7 @@ const Footer = () => { } diff --git a/src/components/NavBar/NavBarSkipLink.jsx b/src/components/NavBar/NavBarSkipLink.jsx index 4900019cf..657657156 100644 --- a/src/components/NavBar/NavBarSkipLink.jsx +++ b/src/components/NavBar/NavBarSkipLink.jsx @@ -41,8 +41,8 @@ const NavBarSkipLink = () => { left: 100, zIndex: 999, transition: 'all 0.3s ease-in-out', - background: theme.palette.accessible.main, - color: theme.palette.accessible.contrastText, + background: theme.palette.background.main, + color: theme.palette.primary.text, opacity: animateOut ? 0 : 1, padding: '5px', transform: animateOut ? 'translateY(-100%)' : 'translateY(0%)' diff --git a/src/theme.js b/src/theme.js index 297efbfc8..789975c91 100644 --- a/src/theme.js +++ b/src/theme.js @@ -2,56 +2,30 @@ import { createTheme } from '@mui/material/styles'; import RedHatDisplay from './fonts/RedHatDisplay-Italic-VariableFont_wght.ttf'; import RedHatText from './fonts/RedHatText-Italic-VariableFont_wght.ttf'; -// theming from Figma - const theme = createTheme({ typography: { button: { textTransform: 'none', fontWeight: 600 }, - // old font family fontFamily: 'RedHatText, sans-serif', - // new font family brand: { fontFamily: 'RedHatDisplay, sans-serif' }, text: { fontFamily: 'RedHatText, sans-serif' } }, palette: { primary: { - // new primary themes strong: '#03295E', background: '#DDECFD', main: '#0758CA', - text: 'black', - - // old primary themes - dark: '#004d3e', - light: '#039686', - slight: '#03295E', - contrastText: '#fff' + text: 'black' }, secondary: { - // new seconday theming weak: '#FFD4C8', main: '#DB562E', - strong: '#822E15', - - // old themes - light: '#b32126', - dark: '#790111', - contrastText: '#fff' - }, - // tertiary old theme - tertiary: { - light: '#dbc584', - main: '#DEBC59', - dark: '#dbb032', - contrastText: '#fff' + strong: '#822E15' }, + status: { - // danger theme is old - danger: '#e53e3e', - // error, success, warning new themes error: { main: '#D3403D', weak: '#FFDEDE', @@ -68,13 +42,11 @@ const theme = createTheme({ strong: '#9E5F00' } }, - // background new theme background: { main: '#FFFFFF', tint: '#EEE8E2', light: '#FAF7F5' }, - // content new theme content: { disabled: '#9C948F', weak: '#786965', @@ -82,24 +54,11 @@ const theme = createTheme({ strong: '#321C15', reverse: '#FFFEFC' }, - // border new theme border: { weak: '#C2BBB6', strong: '#918C88' - }, - // neutral old theme - neutral: { - main: '#64748B', - contrastText: '#fff' - }, - // accessible old theme - accessible: { - main: '#fff', - contrastText: '#0758CA' } }, - // color properties TBD for status snackbar severities - // LOOK INTO THESE components: { MuiCssBaseline: { styleOverrides: ` From 5055b26ead8151961bc3dab1c0b78ca0614759af Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Sun, 28 Apr 2024 19:12:57 -0700 Subject: [PATCH 060/263] fixing test 1 --- src/components/Modals/UploadButtonGroup.jsx | 14 +++++++------- src/components/Modals/UploadDocumentModal.jsx | 7 +------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/components/Modals/UploadButtonGroup.jsx b/src/components/Modals/UploadButtonGroup.jsx index be585c6b5..d461b2cba 100644 --- a/src/components/Modals/UploadButtonGroup.jsx +++ b/src/components/Modals/UploadButtonGroup.jsx @@ -5,8 +5,8 @@ import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined'; import PhotoCameraOutlinedIcon from '@mui/icons-material/PhotoCameraOutlined'; -import InsertPhotoOutlinedIcon from '@mui/icons-material/InsertPhotoOutlined'; -import WebcamModal from './WebcamModal'; +/* import InsertPhotoOutlinedIcon from '@mui/icons-material/InsertPhotoOutlined'; + */ import WebcamModal from './WebcamModal'; /** * The UploadButtonGroup Component is a component that renders the upload document @@ -64,6 +64,7 @@ const UploadButtonGroup = ({ file, setFile }) => { const [showWebcamModal, setShowWebcamModal] = useState(false); const handleCapture = (imageSrc) => { + if (!imageSrc) return; const now = new Date(); const imageFilename = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart( 2, @@ -75,7 +76,6 @@ const UploadButtonGroup = ({ file, setFile }) => { 2, '0' )}.jpg`; - const imageBlob = dataURItoBlob(imageSrc); const imageFile = new File([imageBlob], imageFilename, { type: 'image/jpeg' }); setFile(imageFile); @@ -98,12 +98,12 @@ const UploadButtonGroup = ({ file, setFile }) => { - + */} {hasWebCam ? ( { - {/* */} + {hasWebCam ? ( @@ -132,12 +136,10 @@ const UploadButtonGroup = ({ file, setFile }) => { id="upload-doctype" name="uploadDoctype" onChange={(e) => setFile(e.target.files[0])} - fullWidth required startIcon={} - sx={{ borderRadius: '20px', marginLeft: '8px' }} > - Capture image + Capture Image )} diff --git a/test/components/Modals/UploadButtonGroup.test.jsx b/test/components/Modals/UploadButtonGroup.test.jsx index 1fe2d95ad..6dc07e47b 100644 --- a/test/components/Modals/UploadButtonGroup.test.jsx +++ b/test/components/Modals/UploadButtonGroup.test.jsx @@ -11,11 +11,11 @@ const mockEnumerateDevices = (available) => { }; describe('UploadButtonGroup Component', () => { - it('renders only two buttons', () => { + it('renders only three buttons', () => { global.innerWidth = 1024; const { getAllByRole } = render(); const buttons = getAllByRole('button'); - expect(buttons.length).toBe(2); + expect(buttons.length).toBe(3); }); it('renders use webcam button when webcam exists', async () => { From c214e0d28f7c366c24afaf8aa5bb20558cdacadb Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Mon, 29 Apr 2024 12:10:26 -0700 Subject: [PATCH 066/263] fix spelling change that caused test to break --- test/components/Modals/UploadButtonGroup.test.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/Modals/UploadButtonGroup.test.jsx b/test/components/Modals/UploadButtonGroup.test.jsx index 6dc07e47b..b26345415 100644 --- a/test/components/Modals/UploadButtonGroup.test.jsx +++ b/test/components/Modals/UploadButtonGroup.test.jsx @@ -30,7 +30,7 @@ describe('UploadButtonGroup Component', () => { mockEnumerateDevices(false); const { findByText } = render(); - const captureImageButton = await findByText('Capture image'); + const captureImageButton = await findByText('Capture Image'); // eslint-disable-next-line no-unused-expressions expect(captureImageButton).to.be.ok; }); From f736cef2aa1e2223519b6e7c4c9b2932cd439444 Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Mon, 29 Apr 2024 12:27:19 -0700 Subject: [PATCH 067/263] add consistent theming to messaging inbox/outbox --- .../Messages/MessageButtonGroup.jsx | 2 +- src/components/Messages/MessageFolder.jsx | 6 +++--- src/components/Messages/PaginationStyles.js | 19 +++++++++---------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/components/Messages/MessageButtonGroup.jsx b/src/components/Messages/MessageButtonGroup.jsx index 0e60402e1..320289955 100644 --- a/src/components/Messages/MessageButtonGroup.jsx +++ b/src/components/Messages/MessageButtonGroup.jsx @@ -47,7 +47,7 @@ const MessageButtonGroup = ({ setShowModal, boxType, setBoxType }) => { variant="contained" onClick={() => setShowModal(true)} startIcon={} - color="secondary" + color="primary" > New Message diff --git a/src/components/Messages/MessageFolder.jsx b/src/components/Messages/MessageFolder.jsx index af7f8f477..30d820a60 100644 --- a/src/components/Messages/MessageFolder.jsx +++ b/src/components/Messages/MessageFolder.jsx @@ -103,11 +103,11 @@ const MessageFolder = ({ folderType, handleRefresh, loadMessages, messageList = previousLabel={} renderOnZeroPageCount={null} className="pagination" - previousLinkClassName="page-red" + previousLinkClassName="page-weak-blue" previousClassName="chevron" - nextLinkClassName="page-red" + nextLinkClassName="page-weak-blue" nextClassName="chevron" - pageLinkClassName="page-green" + pageLinkClassName="page-blue" activeLinkClassName="active-page" /> diff --git a/src/components/Messages/PaginationStyles.js b/src/components/Messages/PaginationStyles.js index 6b9b154e3..a2c626544 100644 --- a/src/components/Messages/PaginationStyles.js +++ b/src/components/Messages/PaginationStyles.js @@ -10,8 +10,8 @@ const PaginationContainer = styled.div` gap: 3px; } - .page-green, - .page-red { + .page-blue, + .page-weak-blue { color: #fff; font-weight: bold; padding: 8px 12px; @@ -21,17 +21,16 @@ const PaginationContainer = styled.div` display: flex; } - .page-green { - background-color: #74b0a8; + .page-blue { + background-color: #0758ca; &:hover { - background-color: #017969; + background-color: #03295e; } } - - .page-red { - background-color: #bf7c84; + .page-weak-blue { + background-color: #03295e; &:hover { - background-color: #961020; + background-color: #0758ca; } } @@ -40,7 +39,7 @@ const PaginationContainer = styled.div` } .active-page { - background-color: #017969; + background-color: #0758ca; cursor: default; } `; From c46ca0ff9eb0d2c58400260ab3b68df4a099dda2 Mon Sep 17 00:00:00 2001 From: Jae Gifford Date: Mon, 29 Apr 2024 12:32:45 -0700 Subject: [PATCH 068/263] select only available in small breakpoint --- src/pages/Contacts.jsx | 60 +++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/src/pages/Contacts.jsx b/src/pages/Contacts.jsx index d098d780b..2cd4a2eea 100644 --- a/src/pages/Contacts.jsx +++ b/src/pages/Contacts.jsx @@ -5,7 +5,8 @@ import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Container from '@mui/material/Container'; import Typography from '@mui/material/Typography'; -import { FormControl, Select, MenuItem } from '@mui/material'; +import { FormControl, Select, MenuItem, useMediaQuery } from '@mui/material'; +import { useTheme } from '@mui/system'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; // Component Imports import { useContactsList, useNotification } from '@hooks'; @@ -23,6 +24,9 @@ import { LoadingAnimation, EmptyListNotification } from '@components/Notificatio const Contacts = () => { localStorage.setItem('restorePath', '/contacts'); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + const [showAddContactModal, setShowAddContactModal] = useState(false); const [showConfirmationModal, setShowConfirmationModal] = useState(false); const [processing, setProcessing] = useState(false); @@ -80,37 +84,39 @@ const Contacts = () => { > - - - + {isSmallScreen && ( + + + + )} From f1628a4cb062a035ad59970730a3a38ff685efbd Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 29 Apr 2024 21:30:45 -0700 Subject: [PATCH 069/263] Creating saveToClipboard util --- src/components/Profile/ProfileComponent.jsx | 8 ++++---- src/utils/copy/saveToClipboard.js | 6 ++++++ src/utils/index.js | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 src/utils/copy/saveToClipboard.js diff --git a/src/components/Profile/ProfileComponent.jsx b/src/components/Profile/ProfileComponent.jsx index d4368515f..3a15144f3 100644 --- a/src/components/Profile/ProfileComponent.jsx +++ b/src/components/Profile/ProfileComponent.jsx @@ -12,6 +12,8 @@ import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; // Context Imports import { SignedInUserContext } from '@contexts'; +// Util Imports +import { saveToClipboard } from '@utils'; // Component Inputs import ProfileInputField from './ProfileInputField'; import ProfileEditButtonGroup from './ProfileEditButtonGroup'; @@ -139,8 +141,7 @@ const ProfileComponent = ({ contactProfile, webId }) => { aria-label="Copy WebId" edge="end" onClick={() => { - navigator.clipboard.writeText(webId); - addNotification('success', 'webId copied to clipboard'); + saveToClipboard(webId, 'webId copied to clipboard', addNotification); }} > @@ -158,8 +159,7 @@ const ProfileComponent = ({ contactProfile, webId }) => { aria-label="Copy Invite Link" edge="end" onClick={() => { - navigator.clipboard.writeText(signupLink); - addNotification('success', 'Invite link copied to clipboard'); + saveToClipboard(webId, 'Invite link copied to clipboard', addNotification); }} > diff --git a/src/utils/copy/saveToClipboard.js b/src/utils/copy/saveToClipboard.js new file mode 100644 index 000000000..03b9d97de --- /dev/null +++ b/src/utils/copy/saveToClipboard.js @@ -0,0 +1,6 @@ +const saveToClipboard = (text, message, addNotification) => { + navigator.clipboard.writeText(text); + addNotification('success', message); +}; + +export default saveToClipboard; diff --git a/src/utils/index.js b/src/utils/index.js index d6522dba3..0ec41c7ef 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -9,8 +9,9 @@ import getDriversLicenseData from './barcode/barcode-scan'; import formattedDate from './barcode/barcode-date-parser'; import createPASSContainer, { generateACL } from './pod-management/pod-helper'; +import saveToClipboard from './copy/saveToClipboard'; -export { getDriversLicenseData, formattedDate, createPASSContainer, generateACL }; +export { getDriversLicenseData, formattedDate, createPASSContainer, generateACL, saveToClipboard }; export * from './network/session-core'; export * from './network/session-helper'; From e605fb9348912ba301d04c62a787428659fae119 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 29 Apr 2024 21:37:28 -0700 Subject: [PATCH 070/263] Adding copy function to AddContactModal --- src/components/Modals/AddContactModal.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 0c272566a..8a1a33d48 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -24,6 +24,8 @@ import Tooltip from '@mui/material/Tooltip'; import useNotification from '@hooks/useNotification'; // Constant Imports import { ENV } from '@constants'; +// Util Imports +import { saveToClipboard } from '@utils'; // Component Imports import { FormSection } from '../Form'; @@ -227,7 +229,13 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod InputProps={{ endAdornment: ( - + { + saveToClipboard(webId, 'webId copied to clipboard', addNotification); + }} + > From cdae42e89ae69f93bd78d3a48e65ad5df1d82697 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 29 Apr 2024 23:58:06 -0700 Subject: [PATCH 071/263] Adding JSDocs --- src/utils/barcode/barcode-date-parser.js | 1 - src/utils/copy/saveToClipboard.js | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/barcode/barcode-date-parser.js b/src/utils/barcode/barcode-date-parser.js index 522bec28e..9d88c7c1b 100644 --- a/src/utils/barcode/barcode-date-parser.js +++ b/src/utils/barcode/barcode-date-parser.js @@ -9,7 +9,6 @@ import dayjs from 'dayjs'; * @param {string} dateStr - unformatted date string * @returns {string} newDate.toISOstring.substring(0, 10) - formatted date string */ - const formattedDate = (dateStr) => { const dateStrWithSpaces = dateStr.replace(/(\d{2})(\d{2})(\d{4})/, '$1 $2 $3'); return dayjs(dateStrWithSpaces).toISOString(); diff --git a/src/utils/copy/saveToClipboard.js b/src/utils/copy/saveToClipboard.js index 03b9d97de..d7e3c50de 100644 --- a/src/utils/copy/saveToClipboard.js +++ b/src/utils/copy/saveToClipboard.js @@ -1,3 +1,13 @@ +/** + * Function that saves the provided text to the clipboard and sends the user a notification. + * + * @memberof utils + * @function saveToClipboard + * @param {string} text - Text to be saved to the clipboard + * @param {string} message - Message to be displayed in the notification + * @param {Function} addNotification - Function to display the notification + * @returns {void} - This function does not have a return + */ const saveToClipboard = (text, message, addNotification) => { navigator.clipboard.writeText(text); addNotification('success', message); From 68664de862fcf7b557718242bc61cbadfecc59c7 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 30 Apr 2024 19:22:42 -0700 Subject: [PATCH 072/263] Replacing webId with signupLink --- src/components/Profile/ProfileComponent.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Profile/ProfileComponent.jsx b/src/components/Profile/ProfileComponent.jsx index 3a15144f3..e0461160e 100644 --- a/src/components/Profile/ProfileComponent.jsx +++ b/src/components/Profile/ProfileComponent.jsx @@ -40,13 +40,11 @@ const ProfileComponent = ({ contactProfile, webId }) => { // Public Profile Data const [profileName, setProfileName] = useState(profileData?.profileInfo?.profileName); const [nickname, setNickname] = useState(profileData?.profileInfo?.nickname); - const [edit, setEdit] = useState(false); const loadProfileData = async () => { const profileDataSolid = await fetchProfileInfo(session.info.webId); setProfileData(profileDataSolid); - setProfileName(profileDataSolid.profileInfo?.profileName); setNickname(profileDataSolid.profileInfo?.nickname); }; @@ -159,7 +157,7 @@ const ProfileComponent = ({ contactProfile, webId }) => { aria-label="Copy Invite Link" edge="end" onClick={() => { - saveToClipboard(webId, 'Invite link copied to clipboard', addNotification); + saveToClipboard(signupLink, 'Invite link copied to clipboard', addNotification); }} > From 35d43161e592154d2d179715e55d6bc180598f13 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 30 Apr 2024 20:29:18 -0700 Subject: [PATCH 073/263] Fixing signupLink syntax --- src/components/Profile/ProfileComponent.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Profile/ProfileComponent.jsx b/src/components/Profile/ProfileComponent.jsx index e0461160e..dec2a3c77 100644 --- a/src/components/Profile/ProfileComponent.jsx +++ b/src/components/Profile/ProfileComponent.jsx @@ -157,7 +157,11 @@ const ProfileComponent = ({ contactProfile, webId }) => { aria-label="Copy Invite Link" edge="end" onClick={() => { - saveToClipboard(signupLink, 'Invite link copied to clipboard', addNotification); + saveToClipboard( + `${signupLink}?webId=${encodeURIComponent(session.info.webId)}`, + 'Invite link copied to clipboard', + addNotification + ); }} > From 65b168ccb2f17143a063d867517c9d82a3a73c7b Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 1 May 2024 15:30:14 -0700 Subject: [PATCH 074/263] Created new atomized HousingInfoTextField to use in HousingInfo.jsx. --- .../atomized-components/HousningInfoTextField.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/components/CivicProfileForms/atomized-components/HousningInfoTextField.jsx diff --git a/src/components/CivicProfileForms/atomized-components/HousningInfoTextField.jsx b/src/components/CivicProfileForms/atomized-components/HousningInfoTextField.jsx new file mode 100644 index 000000000..8506d7fe5 --- /dev/null +++ b/src/components/CivicProfileForms/atomized-components/HousningInfoTextField.jsx @@ -0,0 +1,10 @@ +import React /* , { useState, useEffect } */ from 'react'; +import TextField from '@mui/material/TextField'; +// Custom Hooks Imports +// import { useCivicProfile } from '@hooks'; + +const HousingInfoTextField = ({ label, name, value, onChange }) => ( + +); + +export default HousingInfoTextField; From 4bd4b534142293a63ef1765338e1865aa90650e4 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Thu, 2 May 2024 11:51:05 -0700 Subject: [PATCH 075/263] Imported in HousingInfoTextField and used them in form for monthsHomeless, monthsHomeless & timeToHousingLoss data fields. --- .../CivicProfileForms/HousingInfo.jsx | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 95672f694..4903f7cb7 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -5,6 +5,7 @@ import Button from '@mui/material/Button'; import TextField from '@mui/material/TextField'; // Custom Hooks Imports import { useCivicProfile } from '@hooks'; +import HousingInfoTextField from './atomized-components/HousningInfoTextField'; /** * HousingInfo - A form to fill out with housing security info @@ -19,7 +20,10 @@ const HousingInfo = () => { lastPermanentStreet: '', lastPermanentCity: '', lastPermanentState: '', - lastPermanentZIP: '' + lastPermanentZIP: '', + monthsHomeless: '', + timesHomeless: '', + timeToHousingLoss: '' }); useEffect(() => { @@ -85,6 +89,27 @@ const HousingInfo = () => { onChange={handleChange} value={formData.lastPermanentZIP} /> + + + - ); }; From dc5d438a12a90870b82d14c3bb7f81cb1d489ede Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Tue, 7 May 2024 15:51:28 -0700 Subject: [PATCH 077/263] Standardized Add Contact Model with Normal Margins --- src/components/Modals/AddContactModal.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 8a1a33d48..2b791b515 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -164,6 +164,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod /> @@ -190,10 +191,14 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod {!customWebID && ( - + Date: Tue, 7 May 2024 16:04:16 -0700 Subject: [PATCH 078/263] Standardized New Message Model with Normal Margins --- src/components/Modals/NewMessageModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modals/NewMessageModal.jsx b/src/components/Modals/NewMessageModal.jsx index 7a03ff5ec..fd9df1fd6 100644 --- a/src/components/Modals/NewMessageModal.jsx +++ b/src/components/Modals/NewMessageModal.jsx @@ -162,7 +162,7 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' required autoFocus disabled={toField !== ''} - renderInput={(params) => } + renderInput={(params) => } /> Date: Tue, 7 May 2024 18:13:58 -0700 Subject: [PATCH 079/263] Changed main
styling to justifyContent space-around & maxWidth 744px. --- src/components/CivicProfileForms/HousingInfo.jsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 91945bafb..1e6af6289 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -64,8 +64,8 @@ const HousingInfo = () => { style={{ display: 'flex', gap: '8px', - justifyContent: 'space-between', - maxWidth: '720px', + justifyContent: 'space-around', + maxWidth: '744px', padding: '8px' }} > @@ -139,7 +139,16 @@ const HousingInfo = () => { />
-
+
From 8f9b9ed1941f1121789c50915cb9a1129cd443a9 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 8 May 2024 14:29:41 -0700 Subject: [PATCH 080/263] Changed CSS in the main
to `space-around`. --- src/components/CivicProfileForms/HousingInfo.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 1e6af6289..4597bcdf6 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -56,7 +56,7 @@ const HousingInfo = () => { style={{ display: 'flex', gap: '8px', - justifyContent: 'space-between' + justifyContent: 'space-around' // maxWidth: '720px', }} > @@ -65,7 +65,7 @@ const HousingInfo = () => { display: 'flex', gap: '8px', justifyContent: 'space-around', - maxWidth: '744px', + maxWidth: '746px', padding: '8px' }} > From 9a0bcd3f45f51b616f9fd50cc7064ba850aa2d87 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 8 May 2024 15:17:42 -0700 Subject: [PATCH 081/263] Creating ModalBase, importing to existing modals --- src/components/Modals/AddContactModal.jsx | 15 ++++---- src/components/Modals/ModalBase.jsx | 34 +++++++++++++++++++ src/components/Modals/NewMessageModal.jsx | 7 ++-- .../Modals/SetAclPermissionsModal.jsx | 6 ++-- src/components/Modals/UploadDocumentModal.jsx | 11 ++++-- src/components/Modals/WebcamModal.jsx | 1 + 6 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 src/components/Modals/ModalBase.jsx diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 8a1a33d48..6548610cd 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -8,18 +8,17 @@ import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import FormControl from '@mui/material/FormControl'; import IconButton from '@mui/material/IconButton'; import InputAdornment from '@mui/material/InputAdornment'; -import TextField from '@mui/material/TextField'; -import Select from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import Select from '@mui/material/Select'; +import TextField from '@mui/material/TextField'; +import Tooltip from '@mui/material/Tooltip'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; -import Tooltip from '@mui/material/Tooltip'; // Custom Hook Imports import useNotification from '@hooks/useNotification'; // Constant Imports @@ -27,6 +26,7 @@ import { ENV } from '@constants'; // Util Imports import { saveToClipboard } from '@utils'; // Component Imports +import ModalBase from './ModalBase'; import { FormSection } from '../Form'; // @memberof Modals @@ -132,10 +132,11 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod }; return ( - setShowAddContactModal(false)} + anchor="bottom" > @@ -283,7 +284,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod - + ); }; diff --git a/src/components/Modals/ModalBase.jsx b/src/components/Modals/ModalBase.jsx new file mode 100644 index 000000000..2857871f8 --- /dev/null +++ b/src/components/Modals/ModalBase.jsx @@ -0,0 +1,34 @@ +// React Imports +import React from 'react'; +// Material UI Imports +import Dialog from '@mui/material/Dialog'; +import Drawer from '@mui/material/Drawer'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; + +/** + * ModalBase - Component that renders either a modal dialog or drawer based on screen size + * + * @memberof Modals + * @name ModalBase + * @param {object} Props - Props for ModalBase component + * @param {boolean} Props.open - Boolean for opening the modal + * @param {string} Props.arialabelledby - ID of the element that labels the modal + * @param {Function} Props.onClose - Function to call when the modal is closed + * @param {'left'|'top'|'right'|'bottom'} [Props.anchor='left'] - Determines the anchor position for the modal + * @param {React.JSX.Element} Props.children - Content to be displayed within the modal + * @returns {React.JSX.Element} - The rendered modal component + */ +const ModalBase = ({ open, arialabelledby, onClose, anchor, children }) => { + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + const DialogOrDrawer = isSmallScreen ? Drawer : Dialog; + + return ( + + {children} + + ); +}; + +export default ModalBase; diff --git a/src/components/Modals/NewMessageModal.jsx b/src/components/Modals/NewMessageModal.jsx index 7a03ff5ec..a1d4efce8 100644 --- a/src/components/Modals/NewMessageModal.jsx +++ b/src/components/Modals/NewMessageModal.jsx @@ -7,7 +7,6 @@ import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; import ClearIcon from '@mui/icons-material/Clear'; -import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import TextField from '@mui/material/TextField'; import useMediaQuery from '@mui/material/useMediaQuery'; @@ -18,6 +17,7 @@ import { sendMessageTTL } from '@utils'; // Context Imports import { SignedInUserContext } from '@contexts'; // Component Imports +import ModalBase from './ModalBase'; import { FormSection } from '../Form'; /** @@ -120,10 +120,11 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' /* eslint-disable jsx-a11y/label-has-associated-control */ return ( - handleReplyMessage(false)} + anchor="bottom" > { }; return ( - + { - + ); }; diff --git a/src/components/Modals/UploadDocumentModal.jsx b/src/components/Modals/UploadDocumentModal.jsx index 5ef10aea1..9aaf096b4 100644 --- a/src/components/Modals/UploadDocumentModal.jsx +++ b/src/components/Modals/UploadDocumentModal.jsx @@ -4,7 +4,6 @@ import React, { useState, useContext } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import ClearIcon from '@mui/icons-material/Clear'; -import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import FileUploadIcon from '@mui/icons-material/FileUpload'; import FormControl from '@mui/material/FormControl'; @@ -21,6 +20,7 @@ import { useTheme } from '@mui/material/styles'; */ // Context Imports import { DocumentListContext } from '@contexts'; // Component Imports +import ModalBase from './ModalBase'; import { DocumentSelection, FormSection } from '../Form'; import UploadButtonGroup from './UploadButtonGroup'; import useNotification from '../../hooks/useNotification'; @@ -131,7 +131,12 @@ const UploadDocumentModal = ({ showModal, setShowModal }) => { }; return ( - + { - + ); }; diff --git a/src/components/Modals/WebcamModal.jsx b/src/components/Modals/WebcamModal.jsx index 6c0bc1162..411f08136 100644 --- a/src/components/Modals/WebcamModal.jsx +++ b/src/components/Modals/WebcamModal.jsx @@ -3,6 +3,7 @@ import Webcam from 'react-webcam'; import Modal from '@mui/material/Modal'; import Button from '@mui/material/Button'; +// TODO: Determine future of this modal // web camera modal const WebcamModal = ({ open, onClose, onCapture }) => { const webcamRef = useRef(null); From 8bd6f9644a356b223f2264bf78ccbd6dafef72fe Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 8 May 2024 16:14:57 -0700 Subject: [PATCH 082/263] CSS changes to get the fields & container with the help of Joshua Cornett. --- src/components/CivicProfileForms/HousingInfo.jsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 4597bcdf6..e62f66ca2 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -55,8 +55,9 @@ const HousingInfo = () => { onSubmit={handleSubmit} style={{ display: 'flex', + flexDirection: 'column', gap: '8px', - justifyContent: 'space-around' + justifyContent: 'space-between' // maxWidth: '720px', }} > @@ -64,7 +65,7 @@ const HousingInfo = () => { style={{ display: 'flex', gap: '8px', - justifyContent: 'space-around', + // justifyContent: 'space-around', maxWidth: '746px', padding: '8px' }} @@ -141,10 +142,10 @@ const HousingInfo = () => {
Date: Wed, 8 May 2024 16:15:52 -0700 Subject: [PATCH 083/263] Added CSS width: 'unset', with help from Joshua Cornett --- src/pages/CivicProfile.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/CivicProfile.jsx b/src/pages/CivicProfile.jsx index 4119d8161..abd9a651b 100644 --- a/src/pages/CivicProfile.jsx +++ b/src/pages/CivicProfile.jsx @@ -33,7 +33,7 @@ const CivicProfile = () => { - + From 1b3fdb41b0a3592ab420419d725470e374fd84e6 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 8 May 2024 21:03:20 -0700 Subject: [PATCH 084/263] Connecting ModalBase to more modals --- .../CivicProfileForms/BasicInfo.jsx | 2 +- .../CivicProfileForms/FormLayout.jsx | 1 + src/components/Form/FormSection.jsx | 54 ++++++++++++------- src/components/Modals/AddContactModal.jsx | 6 +-- src/components/Modals/ConfirmationModal.jsx | 7 +-- src/components/Modals/ModalBase.jsx | 18 ++++++- .../Modals/SetAclPermissionsModal.jsx | 13 +++-- src/components/Modals/SignInModal.jsx | 2 + src/components/Modals/UploadDocumentModal.jsx | 2 + src/pages/CivicProfile.jsx | 1 + src/pages/Profile.jsx | 2 +- src/pages/Signup.jsx | 9 +--- 12 files changed, 77 insertions(+), 40 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 7eec8ff74..b9ea82a65 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -81,7 +81,7 @@ const BasicInfo = () => { return ( -
+ { const pageIdx = HMIS_FORM_LIST.findIndex((form) => form.path === path); return ( + // TODO: Reevaluate whether we need nested Containers {children} diff --git a/src/components/Form/FormSection.jsx b/src/components/Form/FormSection.jsx index d727b083f..ace7cc013 100644 --- a/src/components/Form/FormSection.jsx +++ b/src/components/Form/FormSection.jsx @@ -3,6 +3,8 @@ import React from 'react'; // Material UI Imports import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; /** * FormSection Component - Component that wraps section with title and MUI Box @@ -17,25 +19,37 @@ import Typography from '@mui/material/Typography'; * @param {React.ReactElement} Props.children - JSX Element of the wrapped form * @returns {React.JSX.Element} - The FormSection Component */ -const FormSection = ({ title, headingId, children }) => ( - - - {title} - - {children} - -); +const FormSection = ({ title, headingId, children }) => { + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + + return ( + + + {title} + + {children} + + ); +}; export default FormSection; diff --git a/src/components/Modals/AddContactModal.jsx b/src/components/Modals/AddContactModal.jsx index 6548610cd..b207a0e2b 100644 --- a/src/components/Modals/AddContactModal.jsx +++ b/src/components/Modals/AddContactModal.jsx @@ -166,7 +166,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod OIDC Provider @@ -191,7 +191,7 @@ const AddContactModal = ({ addContact, showAddContactModal, setShowAddContactMod {!customWebID && ( - + )} {customWebID && ( - + {title.toUpperCase()} @@ -109,7 +110,7 @@ const ConfirmationModal = ({ {confirmButton()} -
+ ); }; diff --git a/src/components/Modals/ModalBase.jsx b/src/components/Modals/ModalBase.jsx index 2857871f8..768a878be 100644 --- a/src/components/Modals/ModalBase.jsx +++ b/src/components/Modals/ModalBase.jsx @@ -14,18 +14,32 @@ import { useTheme } from '@mui/material/styles'; * @param {object} Props - Props for ModalBase component * @param {boolean} Props.open - Boolean for opening the modal * @param {string} Props.arialabelledby - ID of the element that labels the modal + * @param {string} Props.ariadescribedby - ID of the element that describes the modal * @param {Function} Props.onClose - Function to call when the modal is closed * @param {'left'|'top'|'right'|'bottom'} [Props.anchor='left'] - Determines the anchor position for the modal * @param {React.JSX.Element} Props.children - Content to be displayed within the modal * @returns {React.JSX.Element} - The rendered modal component */ -const ModalBase = ({ open, arialabelledby, onClose, anchor, children }) => { +const ModalBase = ({ open, arialabelledby, ariadescribedby, onClose, anchor, children }) => { const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const DialogOrDrawer = isSmallScreen ? Drawer : Dialog; return ( - + {children} ); diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index a55281e8e..2b9385ccf 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -124,7 +124,15 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { } > - + Select One -
{ } renderInput={(params) => } /> -
+ - {confirmButton()} -
- - + + {confirmButton()} +
+ +
+ ); }; diff --git a/src/components/Modals/ModalBase.jsx b/src/components/Modals/ModalBase.jsx index 768a878be..970bb967b 100644 --- a/src/components/Modals/ModalBase.jsx +++ b/src/components/Modals/ModalBase.jsx @@ -34,8 +34,7 @@ const ModalBase = ({ open, arialabelledby, ariadescribedby, onClose, anchor, chi anchor={anchor} PaperProps={{ sx: { - alignItems: 'center', - borderRadius: isSmallScreen ? '15px 15px 0px 0px' : '5px' + borderRadius: isSmallScreen ? '15px 15px 0px 0px' : '15px' // minWidth: '50dvw' } }} diff --git a/src/components/Modals/NewMessageModal.jsx b/src/components/Modals/NewMessageModal.jsx index a1d4efce8..3f634f26d 100644 --- a/src/components/Modals/NewMessageModal.jsx +++ b/src/components/Modals/NewMessageModal.jsx @@ -132,10 +132,10 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' display: 'flex', flexDirection: 'column', justifyContent: 'center', - alignItems: 'center', - padding: '20px', - minWidth: '50%', - minHeight: '90%' + alignItems: 'center' + // padding: '20px', + // minWidth: '50%', + // minHeight: '90%' }} > @@ -155,7 +155,7 @@ const NewMessageModal = ({ showModal, setShowModal, oldMessage = '', toField = ' onChange={(event, newValue) => { setMessage({ ...message, - // if user wants to use a custom webId instead of a contact option, set the recipient value to the typed input + // If user wants to use a custom webId instead of a contact option, set the recipient value to the typed input recipientPodUrl: newValue.id ?? newValue }); }} diff --git a/src/components/Modals/SignInModal.jsx b/src/components/Modals/SignInModal.jsx index 3d72a1359..04e6162e1 100644 --- a/src/components/Modals/SignInModal.jsx +++ b/src/components/Modals/SignInModal.jsx @@ -23,6 +23,7 @@ import OidcLoginComponent from '../NavBar/OidcLoginComponent'; * @returns {React.JSX.Element} - The SignInModal Component */ const SignInModal = ({ showSignInModal, setShowSignInModal }) => ( + // TODO: Determine whether to convert this to a Drawer { setDocDescription(newDocDescription.target.value)} diff --git a/src/components/NavBar/NavMenu.jsx b/src/components/NavBar/NavMenu.jsx index aa179f6c9..6598baaa9 100644 --- a/src/components/NavBar/NavMenu.jsx +++ b/src/components/NavBar/NavMenu.jsx @@ -5,9 +5,11 @@ import { Link } from 'react-router-dom'; import AccountBoxIcon from '@mui/icons-material/AccountBox'; import Avatar from '@mui/material/Avatar'; import Button from '@mui/material/Button'; +// import Backdrop from '@mui/material/Backdrop'; import Badge from '@mui/material/Badge'; import ContactsIcon from '@mui/icons-material/Contacts'; import Divider from '@mui/material/Divider'; +import Drawer from '@mui/material/Drawer'; import EmailIcon from '@mui/icons-material/Email'; import LogoutIcon from '@mui/icons-material/Logout'; import Menu from '@mui/material/Menu'; @@ -18,6 +20,8 @@ import { useTheme } from '@mui/material/styles'; // Context Imports import { DocumentListContext } from '@contexts'; import { useMessageList } from '@hooks'; +// Component Imports +// import ModalBase from '../Modals/ModalBase'; /** * NavMenu Component - Component that generates NavMenu section for PASS @@ -50,7 +54,7 @@ const NavMenu = ({ const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const { setContact } = useContext(DocumentListContext); const { data } = useMessageList('Inbox'); - + const MenuOrDrawer = isSmallScreen ? Drawer : Menu; const numUnreadMessages = data?.reduce((a, m) => (!m.readStatus ? a + 1 : a), 0); const handleMenuClose = () => { @@ -58,31 +62,47 @@ const NavMenu = ({ setAnchorEl(null); }; + const MenuProps = isSmallScreen + ? { + PaperProps: { + sx: { + borderRadius: isSmallScreen ? '0 15px 15px 0px' : '5px' + // width: isSmallScreen ? '75vw' : 0 + // minWidth: '50dvw' + } + } + } + : { + anchorEl, + anchorOrigin: { + vertical: 'bottom', + horizontal: 'right' + }, + transformOrigin: { + vertical: 'top', + horizontal: 'right' + }, + MenuListProps: { disablePadding: true }, + style: { + backgroundColor: 'rgba(0, 0, 0, 0.5)' + }, + slotProps: { + paper: { + style: { + marginTop: '10px' + } + } + } + }; + return ( - {isSmallScreen && ( @@ -181,7 +201,7 @@ const NavMenu = ({ Log Out - + ); }; diff --git a/src/components/Notification/InactivityMessage.jsx b/src/components/Notification/InactivityMessage.jsx index c889bff49..ccb55ffc7 100644 --- a/src/components/Notification/InactivityMessage.jsx +++ b/src/components/Notification/InactivityMessage.jsx @@ -3,6 +3,7 @@ import React, { useState, useEffect, useRef } from 'react'; // Custom Hook Imports import { useSession } from '@hooks'; // Material UI Imports +import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CheckIcon from '@mui/icons-material/Check'; import Dialog from '@mui/material/Dialog'; @@ -11,6 +12,8 @@ import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; import LogoutIcon from '@mui/icons-material/Logout'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; // Component Imports import LogoutButton from '../Modals/LogoutButton'; @@ -28,6 +31,8 @@ const InactivityMessage = () => { const [showPopup, setShowPopup] = useState(false); const [secondsToLogout, setSecondsToLogout] = useState(300); const logoutTimer = useRef(); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); // Toggles the popup after twenty-five minutes of inactivity useEffect(() => { @@ -74,7 +79,7 @@ const InactivityMessage = () => { logout(); setShowPopup(false); } - }, 1000); + }, 1500000); } return () => { clearInterval(logoutTimer.current); @@ -102,20 +107,31 @@ const InactivityMessage = () => { - localStorage.clear()}> - - - + localStorage.clear()}> + + + +
) From e3892e07892658f46aa26311bf630b6e85f6bbb3 Mon Sep 17 00:00:00 2001 From: DionSat <43707506+DionSat@users.noreply.github.com> Date: Thu, 9 May 2024 16:06:55 -0700 Subject: [PATCH 086/263] Standardized Upload Document Modal Margin Normal --- src/components/Modals/UploadDocumentModal.jsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Modals/UploadDocumentModal.jsx b/src/components/Modals/UploadDocumentModal.jsx index 5ef10aea1..fcdf26768 100644 --- a/src/components/Modals/UploadDocumentModal.jsx +++ b/src/components/Modals/UploadDocumentModal.jsx @@ -151,13 +151,14 @@ const UploadDocumentModal = ({ showModal, setShowModal }) => { sx={{ mb: 1 }} /> - -
- + + + + { /> -
{ onChange={(newDocDescription) => setDocDescription(newDocDescription.target.value)} placeholder="Add a description here" /> -
Date: Thu, 9 May 2024 16:14:04 -0700 Subject: [PATCH 087/263] Removed br tags from ACL Permissions Modal --- src/components/Modals/SetAclPermissionsModal.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/Modals/SetAclPermissionsModal.jsx b/src/components/Modals/SetAclPermissionsModal.jsx index c7eb20450..953a05658 100644 --- a/src/components/Modals/SetAclPermissionsModal.jsx +++ b/src/components/Modals/SetAclPermissionsModal.jsx @@ -140,7 +140,6 @@ const SetAclPermissionsModal = ({ showModal, setShowModal, dataset }) => { Unshare
-
{ } renderInput={(params) => } /> -
+ -
+ +
+ +
); }; From bdb6e2a55897a62532234a8c04f0ec40b115ff96 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 29 May 2024 15:16:31 -0700 Subject: [PATCH 125/263] Edited/corrected 's. --- src/components/CivicProfileForms/HousingInfo.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 0755188ca..2808a03be 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -164,7 +164,9 @@ const HousingInfo = () => {
- Months Houseless Past 3 Years: + + Number of Times Houseless Past 3 Years: + Date: Wed, 29 May 2024 16:11:26 -0700 Subject: [PATCH 126/263] Added Grid, CheckIcon & ClearIcon and code for buttons from BassicInfo.jsx to make it work/look like that. --- .../CivicProfileForms/HousingInfo.jsx | 74 +++++++++++++++---- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 2808a03be..f2c97a773 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -2,14 +2,16 @@ import React, { useState, useEffect } from 'react'; // MUI Imports import FormControl from '@mui/material/FormControl'; -// import Grid from '@mui/material/Grid'; -import Button from '@mui/material/Button'; +import Grid from '@mui/material/Grid'; import TextField from '@mui/material/TextField'; import Select from '@mui/material/Select'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; +import Button from '@mui/material/Button'; +import CheckIcon from '@mui/icons-material/Check'; +import ClearIcon from '@mui/icons-material/Clear'; // Custom Hooks Imports -import { useCivicProfile } from '@hooks'; +import { useCivicProfile, useNotification } from '@hooks'; import { FormSection } from '../Form'; /** @@ -19,8 +21,10 @@ import { FormSection } from '../Form'; * @name HousingInfo * @returns {React.JSX.Element} The HousingInfo Component */ + const HousingInfo = () => { const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); + const { addNotification } = useNotification(); const [zipError, setZipError] = useState(false); const [formData, setFormData] = useState({ lastPermanentStreet: '', @@ -42,6 +46,7 @@ const HousingInfo = () => { refetch(); } }, [storedDataset]); + const handleChange = (event) => { const { name, value } = event.target; @@ -57,6 +62,21 @@ const HousingInfo = () => { setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); }; + const handleClear = () => { + setFormData((prevFormData) => ({ + ...prevFormData, + lastPermanentStreet: '', + lastPermanentCity: '', + lastPermanentState: '', + lastPermanentZIP: '', + monthsHomeless: '', + timesHomeless: '', + timeToHousingLoss: '' + })); + + addNotification('success', `Form cleared!`); + }; + const handleSubmit = (e) => { e.preventDefault(); if (!isSuccess || !storedDataset) { @@ -64,6 +84,7 @@ const HousingInfo = () => { } add(formData); + addNotification('success', `Form submitted!`); }; return ( @@ -205,18 +226,41 @@ const HousingInfo = () => { -
- -
+ + + + + + + + + + ); }; From 4c1d54bf6e9a2ec35c9b01d2a5ed722f80571fb5 Mon Sep 17 00:00:00 2001 From: Jae Date: Fri, 31 May 2024 11:15:17 -0700 Subject: [PATCH 127/263] initial HTTP error handling function added --- .../podSignupHelpers/handleHTTPErrors.js | 18 +++++++ .../Signup/podSignupHelpers/registerPod.js | 9 +++- src/pages/Signup.jsx | 52 +++++++++++-------- 3 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 src/components/Signup/podSignupHelpers/handleHTTPErrors.js diff --git a/src/components/Signup/podSignupHelpers/handleHTTPErrors.js b/src/components/Signup/podSignupHelpers/handleHTTPErrors.js new file mode 100644 index 000000000..587fadafe --- /dev/null +++ b/src/components/Signup/podSignupHelpers/handleHTTPErrors.js @@ -0,0 +1,18 @@ +/** + * @param {object} response - HTTP response object + * @param {string} response.message - message body + * @param {number} response.statusCode - HTTP Status Code + * @throws {Error} - message containing error values + * @returns {void} - either throws or nothing + */ +export default function handleIncomingHTTPErrors({ message, statusCode }) { + // extensible with new error codes and messages + if (statusCode !== 400) return; + + switch (message) { + case 'There already is a login for this e-mail address.': + throw new Error(message); + default: + break; + } +} diff --git a/src/components/Signup/podSignupHelpers/registerPod.js b/src/components/Signup/podSignupHelpers/registerPod.js index b3a8966cc..d815cefe8 100644 --- a/src/components/Signup/podSignupHelpers/registerPod.js +++ b/src/components/Signup/podSignupHelpers/registerPod.js @@ -3,6 +3,7 @@ import { generateDpopKeyPair, buildAuthenticatedFetch } from '@inrupt/solid-client-authn-core'; +import handleIncomingHTTPErrors from './handleHTTPErrors'; /** * @typedef RegistrationDoc * @property {string} podUrl - The URL of the pod created during registration @@ -26,8 +27,8 @@ import { const registerPod = async ({ email, password }, oidcProvider) => { // See https://communitysolidserver.github.io/CommunitySolidServer/latest/usage/account/json-api/ // For API - // Create User account, web ID, and Pod + const res = await fetch(`${oidcProvider}.account/`, { headers: { Accepts: 'application/json' } }); const { controls } = await res.json(); const createResp = await fetch(controls.account.create, { method: 'POST' }); @@ -35,16 +36,19 @@ const registerPod = async ({ email, password }, oidcProvider) => { const response = await fetch(`${oidcProvider}.account/`, { headers: { Authorization: `CSS-Account-Token ${newAccountAuth.authorization}` } }); + const { controls: createControls } = await response.json(); const createHeaders = { 'Content-Type': 'application/json', Authorization: `CSS-Account-Token ${newAccountAuth.authorization}` }; - await fetch(createControls.password.create, { + const createControlsResp = await fetch(createControls.password.create, { method: 'POST', headers: createHeaders, body: JSON.stringify({ email, password }) }); + handleIncomingHTTPErrors(await createControlsResp.json()); + const podResp = await fetch(createControls.account.pod, { method: 'POST', headers: createHeaders, @@ -96,6 +100,7 @@ const registerPod = async ({ email, password }, oidcProvider) => { const { access_token: accessToken } = await tokenResponse.json(); const authFetch = await buildAuthenticatedFetch(accessToken, { dpopKey }); + return { podUrl, webId, fetch: authFetch }; }; diff --git a/src/pages/Signup.jsx b/src/pages/Signup.jsx index 5434fa2cf..d871c54d7 100644 --- a/src/pages/Signup.jsx +++ b/src/pages/Signup.jsx @@ -21,6 +21,7 @@ import { registerPod, ExistingPodForm } from '@components/Signup'; +import BasicNotification from '@components/Notification/BasicNotification.jsx'; /** * Signup - First screen in the user registration flow. @@ -38,32 +39,40 @@ const Signup = () => { const [caseManagerName, setCaseManagerName] = useState(); const [step, setStep] = useState('begin'); const [registrationInfo, setRegistrationInfo] = useState({}); + const [httpError, setHttpError] = useState(null); const { session } = useSession(); const registerAndInitialize = async (email, password, confirmPassword) => { setStep('loading'); - const registration = await registerPod( - { - email, - password, - confirmPassword - }, - oidcIssuer - ); - setRegistrationInfo(registration); - const caseManagerNames = caseManagerName?.split(' ') || []; - await initializePod( - registration.webId, - registration.podUrl, - { - caseManagerWebId, - caseManagerFirstName: caseManagerNames[0], - caseManagerLastName: caseManagerNames[caseManagerNames.length - 1] - }, - registration.fetch - ); - setStep('done'); + try { + const registration = await registerPod( + { + email, + password, + confirmPassword + }, + oidcIssuer + ); + setRegistrationInfo(registration); + const caseManagerNames = caseManagerName?.split(' ') || []; + await initializePod( + registration.webId, + registration.podUrl, + { + caseManagerWebId, + caseManagerFirstName: caseManagerNames[0], + caseManagerLastName: caseManagerNames[caseManagerNames.length - 1] + }, + registration.fetch + ); + + setStep('done'); + setHttpError(null); + } catch (error) { + setHttpError(error); + setStep('begin'); + } }; const loadProfileInfo = async () => { @@ -92,6 +101,7 @@ const Signup = () => { return ( + {httpError && } Date: Fri, 31 May 2024 22:51:11 -0700 Subject: [PATCH 128/263] style(HousingInfo): Style the HousingInfo page with MUI Grid(s) (and Flexbox) --- .../CivicProfileForms/HousingInfo.jsx | 103 +++++++----------- 1 file changed, 40 insertions(+), 63 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index f2c97a773..acaf07401 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -89,23 +89,8 @@ const HousingInfo = () => { return ( -
-
+ + { helperText={zipError ? 'Invalid ZIP format. Expected: 12345 or 12345-6789' : ''} /> -
-
+ + Months Houseless Past 3 Years: -
-
- - - - - - - - - + + + + + + + + + + +
); From 4530c178aa92b9be51c690edfbe19934c969437c Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 1 Jun 2024 00:35:20 -0700 Subject: [PATCH 129/263] Adding basic mobile card --- src/components/Contacts/ContactListTable.jsx | 115 ++++++++++++------- src/pages/Contacts.jsx | 12 +- 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index cb8009902..3ef5b4e25 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -2,8 +2,14 @@ import React, { useState } from 'react'; // Material UI Imports import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import ButtonGroup from '@mui/material/ButtonGroup'; +import Card from '@mui/material/Card'; import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; import SendIcon from '@mui/icons-material/Send'; +import Typography from '@mui/material/Typography'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; import { DataGrid, GridToolbarContainer, @@ -11,8 +17,6 @@ import { GridToolbarFilterButton, GridToolbarDensitySelector } from '@mui/x-data-grid'; -// Theme Imports -import theme from '../../theme'; // Component Imports import ContactProfileIcon from './ContactProfileIcon'; import { NewMessageModal } from '../Modals'; @@ -29,7 +33,7 @@ const CustomToolbar = () => ( */ /** - * ContactListTable Component - Component that generates the list of contacts + * ContactListTable - Component that generates the list of contacts * from data within ContactList * * @memberof Contacts @@ -42,10 +46,12 @@ const CustomToolbar = () => ( const ContactListTable = ({ contacts, deleteContact }) => { const [showMessageModal, setShowMessageModal] = useState(false); const [messageToField, setMessageToField] = useState(''); + const theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const handleSendMessage = (contactId) => { setShowMessageModal(!showMessageModal); - setMessageToField(contactId.value.podUrl); + setMessageToField(isSmallScreen ? contactId.podUrl : contactId.value.podUrl); }; const columnTitlesArray = [ @@ -84,7 +90,7 @@ const ContactListTable = ({ contacts, deleteContact }) => { field: 'Message', renderCell: (contactId) => ( handleSendMessage(contactId)} /> ), @@ -111,41 +117,70 @@ const ContactListTable = ({ contacts, deleteContact }) => { return ( - ({ - id: contact.webId, - 'First Name': contact.givenName || '', - 'Last Name': contact.familyName || '', - webId: contact.webId, - Profile: contact, - Message: contact, - Delete: contact - }))} - slots={{ - toolbar: CustomToolbar - }} - sx={{ - '.MuiDataGrid-columnHeader': { - background: theme.palette.primary.light, - color: 'white' - }, - '.MuiDataGrid-columnSeparator': { - display: 'none' - } - }} - pageSizeOptions={[10]} - initialState={{ - pagination: { - paginationModel: { pageSize: 10, page: 0 } - }, - sorting: { - sortModel: [{ field: 'webId', sort: 'asc' }] - } - }} - disableColumnMenu - disableRowSelectionOnClick - /> + {isSmallScreen ? ( + + {contacts?.map((contact) => ( + + + {contact.givenName || ''} {contact.familyName || ''} + + {contact.webId} + + + + + + + ))} + + ) : ( + ({ + id: contact.webId, + 'First Name': contact.givenName || '', + 'Last Name': contact.familyName || '', + webId: contact.webId, + Profile: contact, + Message: contact, + Delete: contact + }))} + slots={{ + toolbar: CustomToolbar + }} + sx={{ + '.MuiDataGrid-columnHeader': { + background: theme.palette.primary.light, + color: 'white' + }, + '.MuiDataGrid-columnSeparator': { + display: 'none' + } + }} + pageSizeOptions={[10]} + initialState={{ + pagination: { + paginationModel: { pageSize: 10, page: 0 } + }, + sorting: { + sortModel: [{ field: 'webId', sort: 'asc' }] + } + }} + disableColumnMenu + disableRowSelectionOnClick + /> + )} Date: Sat, 1 Jun 2024 08:21:09 -0700 Subject: [PATCH 130/263] http error handling added --- .../Signup/podSignupHelpers/handleHTTPErrors.js | 14 +++++++++----- .../Signup/podSignupHelpers/registerPod.js | 2 ++ src/pages/Signup.jsx | 9 +++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/Signup/podSignupHelpers/handleHTTPErrors.js b/src/components/Signup/podSignupHelpers/handleHTTPErrors.js index 587fadafe..b14e86a94 100644 --- a/src/components/Signup/podSignupHelpers/handleHTTPErrors.js +++ b/src/components/Signup/podSignupHelpers/handleHTTPErrors.js @@ -6,13 +6,17 @@ * @returns {void} - either throws or nothing */ export default function handleIncomingHTTPErrors({ message, statusCode }) { - // extensible with new error codes and messages - if (statusCode !== 400) return; + // left as a switch for now, in case different handling will be done based on error code in the future - switch (message) { - case 'There already is a login for this e-mail address.': + switch (statusCode) { + case 400: + throw new Error(message); + case 401: + throw new Error(message); + case 500: throw new Error(message); default: - break; + if (statusCode <= 400) throw new Error(message); + else break; } } diff --git a/src/components/Signup/podSignupHelpers/registerPod.js b/src/components/Signup/podSignupHelpers/registerPod.js index d815cefe8..2e2960e52 100644 --- a/src/components/Signup/podSignupHelpers/registerPod.js +++ b/src/components/Signup/podSignupHelpers/registerPod.js @@ -38,6 +38,7 @@ const registerPod = async ({ email, password }, oidcProvider) => { }); const { controls: createControls } = await response.json(); + const createHeaders = { 'Content-Type': 'application/json', Authorization: `CSS-Account-Token ${newAccountAuth.authorization}` @@ -47,6 +48,7 @@ const registerPod = async ({ email, password }, oidcProvider) => { headers: createHeaders, body: JSON.stringify({ email, password }) }); + handleIncomingHTTPErrors(await createControlsResp.json()); const podResp = await fetch(createControls.account.pod, { diff --git a/src/pages/Signup.jsx b/src/pages/Signup.jsx index d871c54d7..f83643505 100644 --- a/src/pages/Signup.jsx +++ b/src/pages/Signup.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; // Custom Hooks Imports -import { useSession } from '@hooks'; +import { useSession, useNotification } from '@hooks'; // Inrupt Imports import { getThing, getWebIdDataset, getStringNoLocale } from '@inrupt/solid-client'; import { FOAF } from '@inrupt/vocab-common-rdf'; @@ -21,7 +21,6 @@ import { registerPod, ExistingPodForm } from '@components/Signup'; -import BasicNotification from '@components/Notification/BasicNotification.jsx'; /** * Signup - First screen in the user registration flow. @@ -39,7 +38,7 @@ const Signup = () => { const [caseManagerName, setCaseManagerName] = useState(); const [step, setStep] = useState('begin'); const [registrationInfo, setRegistrationInfo] = useState({}); - const [httpError, setHttpError] = useState(null); + const { addNotification } = useNotification(); const { session } = useSession(); @@ -68,9 +67,8 @@ const Signup = () => { ); setStep('done'); - setHttpError(null); } catch (error) { - setHttpError(error); + addNotification('error', error.message); setStep('begin'); } }; @@ -101,7 +99,6 @@ const Signup = () => { return ( - {httpError && } Date: Sat, 1 Jun 2024 10:06:09 -0700 Subject: [PATCH 131/263] added test for email existing --- test/pages/Signup.test.jsx | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/test/pages/Signup.test.jsx b/test/pages/Signup.test.jsx index 510084e66..c16e706e3 100644 --- a/test/pages/Signup.test.jsx +++ b/test/pages/Signup.test.jsx @@ -7,7 +7,16 @@ import { Signup } from '@pages'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { SessionContext } from '@contexts'; import { initializePod, registerPod } from '@components/Signup'; +import { useNotification } from '@hooks'; +vi.mock('@hooks', async () => { + const actual = await vi.importActual('@hooks'); + + return { + ...actual, + useNotification: vi.fn() + }; +}); vi.mock('react-router-dom', async () => { const originalModule = await vi.importActual('react-router-dom'); @@ -23,7 +32,13 @@ vi.mock('@components/Signup', async () => { return { ...orig, initializePod: vi.fn(), - registerPod: vi.fn(() => Promise.resolve({ webId: '', podUrl: '', fetch: vi.fn() })) + registerPod: vi.fn((email) => { + if (email && /emailExists/.test(email)) { + // pretending this email is already in solid + return Promise.reject(new Error()); + } + return Promise.resolve({ webId: '', podUrl: '', fetch: vi.fn() }); + }) }; }); @@ -58,6 +73,7 @@ describe('Signup Page', () => { } } }; + useNotification.mockReturnValue({ addNotification: vi.fn() }); const { getByRole } = render(); expect(getByRole('heading', { name: 'Register For PASS' })).not.toBeNull(); }); @@ -89,9 +105,41 @@ describe('Signup Page', () => { await user.type(confirmPasswordField, confirmPassword); await user.click(getAllByRole('button')[2]); - expect(registerPod).toBeCalledTimes(1); + expect(registerPod).toHaveBeenCalledOnce(); expect(initializePod).toBeCalledTimes(1); }); + it('it fails if email is already registered', async () => { + const session = { + login: vi.fn(), + fetch: vi.fn(), + podUrl: 'https://example.com', + session: { + info: { + webId: 'https://example.com/profile/', + isLoggedIn: false + } + } + }; + useNotification.mockReturnValue({ addNotification: vi.fn() }); + + const user = userEvent.setup(); + const { getByRole, getAllByRole, getByLabelText } = render( + + ); + global.fetch = vi.fn(() => Promise.resolve({ json: vi.fn() })); + const email = 'emailExists@example.com'; + const password = 'password'; + const confirmPassword = 'password'; + const emailField = getByRole('textbox', { name: 'Email' }); + const passwordField = getByLabelText('Password'); + const confirmPasswordField = getByLabelText('Confirm Password'); + + await user.type(emailField, email); + await user.type(passwordField, password); + await user.type(confirmPasswordField, confirmPassword); + await user.click(getAllByRole('button')[2]); + expect(registerPod(emailField.value)).rejects.toThrow(); + }); it('shows pod creation message when logged in', () => { const session = { podUrl: 'https://example.com', From 62f2e319e7824614ad85b43db2e778617bb47a31 Mon Sep 17 00:00:00 2001 From: Jae Date: Tue, 4 Jun 2024 14:31:51 -0700 Subject: [PATCH 132/263] form remounts gets previous data --- src/components/Signup/PodRegistrationForm.jsx | 11 +++++++---- src/pages/Signup.jsx | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/Signup/PodRegistrationForm.jsx b/src/components/Signup/PodRegistrationForm.jsx index b65f091e0..95df3786f 100644 --- a/src/components/Signup/PodRegistrationForm.jsx +++ b/src/components/Signup/PodRegistrationForm.jsx @@ -36,12 +36,15 @@ const textFieldStyle = { * @param {object} props - Component props * @param {Function} props.register - The function to handle user registration * @param {string} props.caseManagerName - The name of the case manager (optional) + * @param {object} props.previousInfo - previous info in case an error occurs * @returns {React.Element} The rendered React component */ -const PodRegistrationForm = ({ register, caseManagerName }) => { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [confirmPassword, setConfirmPassword] = useState(''); +const PodRegistrationForm = ({ register, caseManagerName, previousInfo = null }) => { + const [email, setEmail] = useState(previousInfo ? previousInfo.email : ''); + const [password, setPassword] = useState(previousInfo ? previousInfo.password : ''); + const [confirmPassword, setConfirmPassword] = useState( + previousInfo ? previousInfo.confirmPassword : '' + ); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); diff --git a/src/pages/Signup.jsx b/src/pages/Signup.jsx index f83643505..7512e5f9f 100644 --- a/src/pages/Signup.jsx +++ b/src/pages/Signup.jsx @@ -39,11 +39,13 @@ const Signup = () => { const [step, setStep] = useState('begin'); const [registrationInfo, setRegistrationInfo] = useState({}); const { addNotification } = useNotification(); + const [previousInfo, setPreviousInfo] = useState(null); const { session } = useSession(); const registerAndInitialize = async (email, password, confirmPassword) => { setStep('loading'); + setPreviousInfo({ email, password, confirmPassword }); try { const registration = await registerPod( { @@ -67,8 +69,8 @@ const Signup = () => { ); setStep('done'); - } catch (error) { - addNotification('error', error.message); + } catch (httpError) { + addNotification('error', httpError.message); setStep('begin'); } }; @@ -121,6 +123,7 @@ const Signup = () => { {step === 'begin' && ( <> From 7d95df36612fdf96cb1dbc3625f79a8cb6f83947 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 17:31:02 -0700 Subject: [PATCH 133/263] Changed mock values for what are now ``'s instead of ``, so the tests will pass. --- test/components/CivicProfileForms/HousingInfo.test.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/components/CivicProfileForms/HousingInfo.test.jsx b/test/components/CivicProfileForms/HousingInfo.test.jsx index 96a925fb8..37559b787 100644 --- a/test/components/CivicProfileForms/HousingInfo.test.jsx +++ b/test/components/CivicProfileForms/HousingInfo.test.jsx @@ -45,11 +45,11 @@ describe('Housing info form', () => { const streetField = getByRole('textbox', { name: 'Street:' }); const stateField = getByRole('textbox', { name: 'State:' }); const zipField = getByRole('textbox', { name: 'ZIP Code:' }); - const monthsHomelessField = getByRole('textbox', { name: 'Months Houseless Past 3 Years:' }); - const timesHomelessField = getByRole('textbox', { + const monthsHomelessField = getByRole('option', { name: 'Months Houseless Past 3 Years:' }); + const timesHomelessField = getByRole('option', { name: 'Number of Times Houseless Past 3 Years:' }); - const timeToHousingLossField = getByRole('textbox', { name: 'Time Until Loss of Housing:' }); + const timeToHousingLossField = getByRole('option', { name: 'Time Until Loss of Housing:' }); const submitButton = getByRole('button'); await user.type(cityField, address.lastPermanentCity); await user.type(streetField, address.lastPermanentStreet); From e84ecb2fc35bc0c08300bcd8349c12d255bc305f Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 17:46:44 -0700 Subject: [PATCH 135/263] Changed mock options for `monthsHomeless`, `timesHomeless`, & `timeToHousingLoss` to match HUD `hmis-interop` values & made their `getByRole` an `option`, as it is now a `` fields so the Vitests will pass. --- src/components/CivicProfileForms/HousingInfo.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index acaf07401..1238cca1e 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -136,6 +136,7 @@ const HousingInfo = () => { Months Houseless Past 3 Years: { Time Until Loss of Housing: )} From d9976467476ee1a680c08c879e5f7d489bfea573 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 19:53:50 -0700 Subject: [PATCH 143/263] Per @KaHungLee, aded the conditional for `zipError` and an error Notification to `handleSubmit(...)`. --- src/components/CivicProfileForms/HousingInfo.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index c316bd725..1a79f2e80 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -79,7 +79,8 @@ const HousingInfo = () => { const handleSubmit = (e) => { e.preventDefault(); - if (!isSuccess || !storedDataset) { + if (!isSuccess || !storedDataset || zipError) { + addNotification('error', 'Form error. Please check for errors.'); return; } From c6c57fab7f4e3d41b7097b138d0f26ce52b3f7e8 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 20:03:47 -0700 Subject: [PATCH 144/263] Changed `addNotification` to `useNotification`, as we were getting `addNotification() is not a function` in Vitest. --- src/components/CivicProfileForms/HousingInfo.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 1a79f2e80..933346e72 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -24,7 +24,7 @@ import { FormSection } from '../Form'; const HousingInfo = () => { const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); - const { addNotification } = useNotification(); + // const { addNotification } = useNotification(); const [zipError, setZipError] = useState(false); const [formData, setFormData] = useState({ lastPermanentStreet: '', @@ -74,18 +74,18 @@ const HousingInfo = () => { timeToHousingLoss: '' })); - addNotification('success', `Form cleared!`); + useNotification('success', `Form cleared!`); }; const handleSubmit = (e) => { e.preventDefault(); if (!isSuccess || !storedDataset || zipError) { - addNotification('error', 'Form error. Please check for errors.'); + useNotification('error', 'Form error. Please check for errors.'); return; } add(formData); - addNotification('success', `Form submitted!`); + useNotification('success', `Form submitted!`); }; return ( From eac89ebab379825eb45546117ba2468ade12e68c Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 20:36:01 -0700 Subject: [PATCH 145/263] Re-did declaration of `addNotification()` & added it back in throughout to get Vitests to pass. --- src/components/CivicProfileForms/HousingInfo.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 933346e72..37b5ec69e 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -24,7 +24,7 @@ import { FormSection } from '../Form'; const HousingInfo = () => { const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); - // const { addNotification } = useNotification(); + const addNotification = useNotification(); const [zipError, setZipError] = useState(false); const [formData, setFormData] = useState({ lastPermanentStreet: '', @@ -74,18 +74,18 @@ const HousingInfo = () => { timeToHousingLoss: '' })); - useNotification('success', `Form cleared!`); + addNotification('success', `Form cleared!`); }; const handleSubmit = (e) => { e.preventDefault(); if (!isSuccess || !storedDataset || zipError) { - useNotification('error', 'Form error. Please check for errors.'); + addNotification('error', 'Form error. Please check for errors.'); return; } add(formData); - useNotification('success', `Form submitted!`); + addNotification('success', `Form submitted!`); }; return ( From 4008177d1697559076a7e0d900ff3d2138138b48 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Tue, 4 Jun 2024 20:44:01 -0700 Subject: [PATCH 146/263] Re-did `addNotification()` declaration within `{ addNotification }` so it will now hopefully work. --- src/components/CivicProfileForms/HousingInfo.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 37b5ec69e..1a79f2e80 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -24,7 +24,7 @@ import { FormSection } from '../Form'; const HousingInfo = () => { const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); - const addNotification = useNotification(); + const { addNotification } = useNotification(); const [zipError, setZipError] = useState(false); const [formData, setFormData] = useState({ lastPermanentStreet: '', From c11d567c154ca38f07cd10c34432e9df37c5d415 Mon Sep 17 00:00:00 2001 From: Ka Hung Lee Date: Tue, 4 Jun 2024 22:56:16 -0700 Subject: [PATCH 147/263] Update unit tests --- .../CivicProfileForms/HousingInfo.test.jsx | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/test/components/CivicProfileForms/HousingInfo.test.jsx b/test/components/CivicProfileForms/HousingInfo.test.jsx index e2595decf..c755b6958 100644 --- a/test/components/CivicProfileForms/HousingInfo.test.jsx +++ b/test/components/CivicProfileForms/HousingInfo.test.jsx @@ -1,8 +1,8 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { vi, expect, it, describe } from 'vitest'; import { HousingInfo } from '@components/CivicProfileForms'; -import { useCivicProfile } from '@hooks'; +import { useCivicProfile, useNotification } from '@hooks'; import userEvent from '@testing-library/user-event'; vi.mock('@hooks', async () => { @@ -10,13 +10,15 @@ vi.mock('@hooks', async () => { return { ...actual, - useCivicProfile: vi.fn() + useCivicProfile: vi.fn(), + useNotification: vi.fn() }; }); describe('Housing info form', () => { it('renders', () => { useCivicProfile.mockReturnValue({ data: {}, isSuccess: true, refetch: vi.fn() }); + useNotification.mockReturnValue({ addNotification: vi.fn() }); const { getByRole } = render(); const cityField = getByRole('textbox', { name: 'City:' }); expect(cityField).not.toBeNull(); @@ -40,28 +42,36 @@ describe('Housing info form', () => { storedDataset: {}, refetch: vi.fn() }); + useNotification.mockReturnValue({ addNotification: vi.fn() }); const { getByRole } = render(); const cityField = getByRole('textbox', { name: 'City:' }); const streetField = getByRole('textbox', { name: 'Street:' }); const stateField = getByRole('textbox', { name: 'State:' }); const zipField = getByRole('textbox', { name: 'ZIP Code:' }); - const monthsHomelessField = getByRole('option', { name: 'Months Houseless Past 3 Years:' }); - const timesHomelessField = getByRole('option', { + const monthsHomelessField = getByRole('combobox', { name: 'Months Houseless Past 3 Years:' }); + const timesHomelessField = getByRole('combobox', { name: 'Number of Times Houseless Past 3 Years:' }); - const timeToHousingLossField = getByRole('option', { name: 'Time Until Loss of Housing:' }); + const timeToHousingLossField = getByRole('combobox', { name: 'Time Until Loss of Housing:' }); const submitButton = getByRole('button', { name: 'Submit button' }); - const clearButton = getByRole('button', { name: 'Clear button' }); await user.type(cityField, address.lastPermanentCity); await user.type(streetField, address.lastPermanentStreet); await user.type(stateField, address.lastPermanentState); await user.type(zipField, address.lastPermanentZIP); - await user.type(monthsHomelessField, address.monthsHomeless); - await user.type(timesHomelessField, address.timesHomeless); - await user.type(timeToHousingLossField, address.timeToHousingLoss); + await user.click(monthsHomelessField); + await user.click(screen.getByRole('option', { name: address.monthsHomeless })); + await user.click(timesHomelessField); + await user.click(screen.getByRole('option', { name: address.timesHomeless })); + await user.click(timeToHousingLossField); + await user.click(screen.getByRole('option', { name: address.timeToHousingLoss })); await user.click(submitButton); - await user.click(clearButton); - expect(mockAdd).toBeCalledWith(address); + + expect(mockAdd).toBeCalledWith({ + ...address, + monthsHomeless: 103, + timeToHousingLoss: 1, + timesHomeless: 2 + }); }); it('does not submit when storedDataset is null', async () => { const user = userEvent.setup(); @@ -86,22 +96,24 @@ describe('Housing info form', () => { const streetField = getByRole('textbox', { name: 'Street:' }); const stateField = getByRole('textbox', { name: 'State:' }); const zipField = getByRole('textbox', { name: 'ZIP Code:' }); - const monthsHomelessField = getByRole('option', { name: 'Months Houseless Past 3 Years:' }); - const timesHomelessField = getByRole('option', { + const monthsHomelessField = getByRole('combobox', { name: 'Months Houseless Past 3 Years:' }); + const timesHomelessField = getByRole('combobox', { name: 'Number of Times Houseless Past 3 Years:' }); - const timeToHousingLossField = getByRole('option', { name: 'Time Until Loss of Housing:' }); + const timeToHousingLossField = getByRole('combobox', { name: 'Time Until Loss of Housing:' }); const submitButton = getByRole('button', { name: 'Submit button' }); - const clearButton = getByRole('button', { name: 'Clear button' }); await user.type(cityField, address.lastPermanentCity); await user.type(streetField, address.lastPermanentStreet); await user.type(stateField, address.lastPermanentState); await user.type(zipField, address.lastPermanentZIP); - await user.type(monthsHomelessField, address.monthsHomeless); - await user.type(timesHomelessField, address.timesHomeless); - await user.type(timeToHousingLossField, address.timeToHousingLoss); + await user.click(monthsHomelessField); + await user.click(screen.getByRole('option', { name: address.monthsHomeless })); + await user.click(timesHomelessField); + await user.click(screen.getByRole('option', { name: address.timesHomeless })); + await user.click(timeToHousingLossField); + await user.click(screen.getByRole('option', { name: address.timeToHousingLoss })); await user.click(submitButton); - await user.click(clearButton); + expect(mockAdd).not.toBeCalled(); }); }); From c342b00db58b10b1dad0736311b6ca4800295fab Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 5 Jun 2024 17:02:00 -0700 Subject: [PATCH 148/263] Removed `role` from each ``'s to be 99, the `'Deta not collected'` option. --- src/components/CivicProfileForms/HousingInfo.jsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 1a79f2e80..16ed812ab 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -31,9 +31,9 @@ const HousingInfo = () => { lastPermanentCity: '', lastPermanentState: '', lastPermanentZIP: '', - monthsHomeless: '', - timesHomeless: '', - timeToHousingLoss: '' + monthsHomeless: 99, + timesHomeless: 99, + timeToHousingLoss: 99 }); useEffect(() => { @@ -69,9 +69,9 @@ const HousingInfo = () => { lastPermanentCity: '', lastPermanentState: '', lastPermanentZIP: '', - monthsHomeless: '', - timesHomeless: '', - timeToHousingLoss: '' + monthsHomeless: 99, + timesHomeless: 99, + timeToHousingLoss: 99 })); addNotification('success', `Form cleared!`); @@ -137,7 +137,6 @@ const HousingInfo = () => { Months Houseless Past 3 Years: { Time Until Loss of Housing: ` fields are tested with `expect` looking at `firstChild.textContent` for each to be `'Data not collected'`. --- .../CivicProfileForms/HousingInfo.test.jsx | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/components/CivicProfileForms/HousingInfo.test.jsx b/test/components/CivicProfileForms/HousingInfo.test.jsx index c755b6958..464ec158f 100644 --- a/test/components/CivicProfileForms/HousingInfo.test.jsx +++ b/test/components/CivicProfileForms/HousingInfo.test.jsx @@ -116,4 +116,58 @@ describe('Housing info form', () => { expect(mockAdd).not.toBeCalled(); }); + + it('clears all input fields when you click the clear button', async () => { + const user = userEvent.setup(); + const mockClear = vi.fn(); + const address = { + lastPermanentStreet: '20th ave', + lastPermanentCity: 'Portland', + lastPermanentState: 'Oregon', + lastPermanentZIP: '97205', + monthsHomeless: '1 Month', + timesHomeless: 'One Time', + timeToHousingLoss: '7-13 Days' + }; + useCivicProfile.mockReturnValue({ + add: mockClear, + isSuccess: true, + storedDataset: {}, + refetch: vi.fn() + }); + + useNotification.mockReturnValue({ addNotification: vi.fn() }); + const { getByRole } = render(); + const cityField = getByRole('textbox', { name: 'City:' }); + const streetField = getByRole('textbox', { name: 'Street:' }); + const stateField = getByRole('textbox', { name: 'State:' }); + const zipField = getByRole('textbox', { name: 'ZIP Code:' }); + const monthsHomelessField = getByRole('combobox', { name: 'Months Houseless Past 3 Years:' }); + const timesHomelessField = getByRole('combobox', { + name: 'Number of Times Houseless Past 3 Years:' + }); + const timeToHousingLossField = getByRole('combobox', { name: 'Time Until Loss of Housing:' }); + const clearButton = getByRole('button', { name: 'Clear button' }); + + await user.type(streetField, address.lastPermanentStreet); + await user.type(cityField, address.lastPermanentCity); + await user.type(stateField, address.lastPermanentState); + await user.type(zipField, address.lastPermanentZIP); + await user.click(monthsHomelessField); + await user.click(screen.getByRole('option', { name: address.monthsHomeless })); + await user.click(timesHomelessField); + await user.click(screen.getByRole('option', { name: address.timesHomeless })); + await user.click(timeToHousingLossField); + await user.click(screen.getByRole('option', { name: address.timeToHousingLoss })); + + await user.click(clearButton); + + expect(streetField.value).toBe(''); + expect(cityField.value).toBe(''); + expect(stateField.value).toBe(''); + expect(zipField.value).toBe(''); + expect(monthsHomelessField.firstChild.textContent).toBe('Data not collected'); + expect(timesHomelessField.firstChild.textContent).toBe('Data not collected'); + expect(timeToHousingLossField.firstChild.textContent).toBe('Data not collected'); + }); }); From 9981b3e4869124ffcbcb8969eab8306fd99a53cf Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Wed, 5 Jun 2024 18:35:43 -0700 Subject: [PATCH 150/263] Delete PASS.code-workspace Deleted erroneous PASS.code-workspace from @faddah's local drive. --- PASS.code-workspace | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 PASS.code-workspace diff --git a/PASS.code-workspace b/PASS.code-workspace deleted file mode 100644 index 75d194d5e..000000000 --- a/PASS.code-workspace +++ /dev/null @@ -1,29 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "workbench.colorCustomizations": { - "activityBar.activeBackground": "#7f40bf", - "activityBar.background": "#7f40bf", - "activityBar.foreground": "#e7e7e7", - "activityBar.inactiveForeground": "#e7e7e799", - "activityBarBadge.background": "#c78f58", - "activityBarBadge.foreground": "#15202b", - "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#7f40bf", - "statusBar.background": "#663399", - "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#7f40bf", - "statusBarItem.remoteBackground": "#663399", - "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#663399", - "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#66339999", - "titleBar.inactiveForeground": "#e7e7e799" - }, - "peacock.color": "#639" - } -} \ No newline at end of file From 4808fdff29d61c9755a81611cfef77a3436db1d2 Mon Sep 17 00:00:00 2001 From: Faddah Wolf Date: Thu, 6 Jun 2024 04:03:20 -0700 Subject: [PATCH 151/263] Per Issue #646, switched order in `npm start` to run podserver first, then npm run dev. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a17b281f..98681601c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.12.0", "description": "", "scripts": { - "start": "concurrently --kill-others \"npm run dev\" \"npm run podserver\"", + "start": "concurrently --kill-others \"npm run podserver\" \"npm run dev\"", "dev": "vite --host", "build": "vite build", "test": "vitest", From 8eb24fd63626a174cb5fb557c1a975576c471152 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 7 Jun 2024 13:43:12 -0700 Subject: [PATCH 152/263] Beginning abstraction of desktop contacts table --- src/components/Contacts/ContactListTable.jsx | 208 ++++++++++++------ .../Contacts/ContactListTableDesktop.jsx | 154 +++++++++++++ .../Contacts/ContactListTableMobile.jsx | 41 ++++ .../Contacts/ContactProfileIcon.jsx | 6 +- src/components/Contacts/index.js | 4 +- .../Contacts/ContactsListTable.test.jsx | 30 ++- 6 files changed, 373 insertions(+), 70 deletions(-) create mode 100644 src/components/Contacts/ContactListTableDesktop.jsx create mode 100644 src/components/Contacts/ContactListTableMobile.jsx diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 7a0d3a705..0993677e2 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -5,6 +5,7 @@ import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; import Grid from '@mui/material/Grid'; import IconButton from '@mui/material/IconButton'; @@ -22,9 +23,15 @@ import { GridToolbarFilterButton, GridToolbarDensitySelector } from '@mui/x-data-grid'; +// Custom Hooks Imports +import useNotification from '@hooks/useNotification'; +// Util Imports +import { saveToClipboard } from '@utils'; // Component Imports import ContactProfileIcon from './ContactProfileIcon'; import { NewMessageModal } from '../Modals'; +// import ContactListTableDesktop from './ContactListTableDesktop' +// import ContactListTableMobile from './ContactListTableMobile' const CustomToolbar = () => ( @@ -51,27 +58,33 @@ const CustomToolbar = () => ( const ContactListTable = ({ contacts, deleteContact }) => { const [showMessageModal, setShowMessageModal] = useState(false); const [messageToField, setMessageToField] = useState(''); - + const { addNotification } = useNotification(); + const [anchorEl, setAnchorEl] = useState(null); + const [openMenu, setOpenMenu] = useState(null); const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const handleClick = (event) => { + const handleClick = (event, contact) => { setAnchorEl(event.currentTarget); + setOpenMenu(contact.webId); }; const handleClose = () => { setAnchorEl(null); + setOpenMenu(null); + }; + + const handleMenuItemClick = (action, contact) => () => { + action(contact); + handleClose(); }; const handleSendMessage = (contactId) => { setShowMessageModal(!showMessageModal); setMessageToField(isSmallScreen ? contactId.podUrl : contactId.value.podUrl); - setAnchorEl(null); }; - const handleProfileClick = () => { - setAnchorEl(null); + const handleProfileClick = (value) => { + console.log(value); }; const columnTitlesArray = [ @@ -99,7 +112,10 @@ const ContactListTable = ({ contacts, deleteContact }) => { }, { field: 'Profile', - renderCell: (contactData) => handleProfileClick(contactData)} />, + renderCell: (contactData) => ( + + // handleProfileClick(contactData)} /> + ), sortable: false, filterable: false, width: 80, @@ -135,87 +151,151 @@ const ContactListTable = ({ contacts, deleteContact }) => { } ]; + const iconSize = { + height: '24px', + width: '24px' + }; + + const iconStyling = { + width: '100%' + }; + return ( {isSmallScreen ? ( + + + + First Name + + + Last Name + + + Actions + + + {contacts?.map((contact) => ( - - - - {contact.givenName || ''} {contact.familyName || ''} - - - {contact.webId} - - + + + {contact.givenName || ''} + + + + + {contact.familyName || ''} + - + + + {contact.webId} + + + handleClick(event, contact)} > - + + - + + saveToClipboard( + contact.webId, + 'webId copied to clipboard', + addNotification + ), + contact + )} + startIcon={} + sx={iconStyling} > - handleProfileClick(contact)} - startIcon={} - > - Profile - - handleSendMessage(contact)} - startIcon={ - - } - > - Message - - deleteContact(contact)} - startIcon={} - > - Delete - - - + Copy WebId + + } + sx={iconStyling} + > + Profile + + + } + sx={iconStyling} + > + Message + + } + sx={iconStyling} + > + Delete + + ))} @@ -238,7 +318,7 @@ const ContactListTable = ({ contacts, deleteContact }) => { sx={{ '.MuiDataGrid-columnHeader': { background: theme.palette.primary.light, - color: 'white' + color: '#fff' }, '.MuiDataGrid-columnSeparator': { display: 'none' diff --git a/src/components/Contacts/ContactListTableDesktop.jsx b/src/components/Contacts/ContactListTableDesktop.jsx new file mode 100644 index 000000000..b5078c589 --- /dev/null +++ b/src/components/Contacts/ContactListTableDesktop.jsx @@ -0,0 +1,154 @@ +// React Imports +import React from 'react'; +// Material UI Imports +import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; +import SendIcon from '@mui/icons-material/Send'; +import { useTheme } from '@mui/material/styles'; +import { + DataGrid, + GridToolbarContainer, + GridActionsCellItem, + GridToolbarFilterButton, + GridToolbarDensitySelector +} from '@mui/x-data-grid'; +// Component Imports +import ContactProfileIcon from './ContactProfileIcon'; + +const CustomToolbar = () => ( + + + + +); + +/** + * @typedef {object} Contact + * @property {string} webId - The Web ID of the contact + * @property {string} givenName - The given name of the contact + * @property {string} familyName - The family name of the contact + */ + +/** + * ContactListTableDesktop - Component for displaying contacts in a DataGrid + * + * @memberof Contacts + * @name ContactListTableDesktop + * @param {object} Props - The props for ContactListTableDesktop + * @param {Contact[]} Props.contacts - The list of contacts to display + * @param {Function} Props.deleteContact - Function to delete a contact + * @param {Function} Props.handleSendMessage - Function to handle sending a message +// * @param {Function} Props.handleProfileClick - Function to handle profile click + * @returns {React.JSX.Element} The ContactListTableDesktop component + */ +const ContactListTableDesktop = ({ + contacts, + deleteContact, + handleSendMessage + // handleProfileClick +}) => { + const theme = useTheme(); + + const columnTitlesArray = [ + { + field: 'First Name', + minWidth: 120, + flex: 1, + headerAlign: 'center', + align: 'center' + }, + { + field: 'Last Name', + minWidth: 120, + flex: 1, + headerAlign: 'center', + align: 'center' + }, + { + field: 'webId', + headerName: 'Web ID', + minWidth: 150, + flex: 1, + headerAlign: 'center', + align: 'center' + }, + { + field: 'Profile', + renderCell: (contactData) => ( + + // handleProfileClick(contactData)} /> + ), + sortable: false, + filterable: false, + width: 80, + headerAlign: 'center', + align: 'center' + }, + { + field: 'Message', + renderCell: (contactId) => ( + handleSendMessage(contactId)} + /> + ), + sortable: false, + filterable: false, + width: 80, + headerAlign: 'center', + align: 'center' + }, + { + field: 'actions', + type: 'actions', + headerName: 'Delete', + width: 80, + getActions: (contactData) => [ + } + onClick={() => deleteContact(contactData.row.Delete)} + label="Delete" + /> + ] + } + ]; + + return ( + ({ + id: contact.webId, + 'First Name': contact.givenName || '', + 'Last Name': contact.familyName || '', + webId: contact.webId, + Profile: contact, + Message: contact, + Delete: contact + }))} + slots={{ + toolbar: CustomToolbar + }} + sx={{ + '.MuiDataGrid-columnHeader': { + background: theme.palette.primary.light, + color: '#fff' + }, + '.MuiDataGrid-columnSeparator': { + display: 'none' + } + }} + pageSizeOptions={[10]} + initialState={{ + pagination: { + paginationModel: { pageSize: 10, page: 0 } + }, + sorting: { + sortModel: [{ field: 'webId', sort: 'asc' }] + } + }} + disableColumnMenu + disableRowSelectionOnClick + /> + ); +}; + +export default ContactListTableDesktop; diff --git a/src/components/Contacts/ContactListTableMobile.jsx b/src/components/Contacts/ContactListTableMobile.jsx new file mode 100644 index 000000000..ea22f76a3 --- /dev/null +++ b/src/components/Contacts/ContactListTableMobile.jsx @@ -0,0 +1,41 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable arrow-body-style */ +// React Imports +import React, { useState } from 'react'; +// Material UI Imports +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; +import Grid from '@mui/material/Grid'; +import IconButton from '@mui/material/IconButton'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import SendIcon from '@mui/icons-material/Send'; +import Typography from '@mui/material/Typography'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; +import { + DataGrid, + GridToolbarContainer, + GridActionsCellItem, + GridToolbarFilterButton, + GridToolbarDensitySelector +} from '@mui/x-data-grid'; +// Custom Hooks Imports +import useNotification from '@hooks/useNotification'; +// Util Imports +import { saveToClipboard } from '@utils'; +// Component Imports +import ContactProfileIcon from './ContactProfileIcon'; +import { NewMessageModal } from '../Modals'; + +// JSDocs +const ContactListTableMobile = () => { + return
ContactListTableMobile
; +}; + +export default ContactListTableMobile; diff --git a/src/components/Contacts/ContactProfileIcon.jsx b/src/components/Contacts/ContactProfileIcon.jsx index 342a56573..b965e3b52 100644 --- a/src/components/Contacts/ContactProfileIcon.jsx +++ b/src/components/Contacts/ContactProfileIcon.jsx @@ -20,7 +20,7 @@ import { DocumentListContext } from '@contexts'; */ /** - * ContactProfileIcon Component - Component that generates the contact profile + * ContactProfileIcon - Component that generates the contact profile * icon for the Contacts List which is a special link to their profile page * * @memberof Contacts @@ -35,10 +35,12 @@ const ContactProfileIcon = ({ contact }) => { // Event handler for profile page routing const handleSelectProfile = async (contactInfo) => { + console.log(`contactInfo: ${contactInfo}`); try { await getWebIdDataset(contactInfo.webId); setContact(contactInfo); - } catch { + } catch (error) { + console.error('Error fetching webId dataset:', error); setContact(null); navigate('/contacts'); addNotification('error', 'WebId does not exist'); diff --git a/src/components/Contacts/index.js b/src/components/Contacts/index.js index 50fa85800..60ea1f93d 100644 --- a/src/components/Contacts/index.js +++ b/src/components/Contacts/index.js @@ -1,4 +1,6 @@ import ContactListTable from './ContactListTable'; +import ContactListTableDesktop from './ContactListTableDesktop'; +import ContactListTableMobile from './ContactListTableMobile'; import ContactProfileIcon from './ContactProfileIcon'; /** @@ -7,4 +9,4 @@ import ContactProfileIcon from './ContactProfileIcon'; * @namespace Contacts */ -export { ContactListTable, ContactProfileIcon }; +export { ContactListTable, ContactListTableDesktop, ContactListTableMobile, ContactProfileIcon }; diff --git a/test/components/Contacts/ContactsListTable.test.jsx b/test/components/Contacts/ContactsListTable.test.jsx index 840334563..69592e8aa 100644 --- a/test/components/Contacts/ContactsListTable.test.jsx +++ b/test/components/Contacts/ContactsListTable.test.jsx @@ -1,9 +1,15 @@ import React from 'react'; -import { render } from '@testing-library/react'; -import { expect, it } from 'vitest'; import { BrowserRouter } from 'react-router-dom'; -import { ContactListTable } from '@components/Contacts'; +import { render, cleanup } from '@testing-library/react'; +import { afterEach, expect, it } from 'vitest'; +// import { SessionContext } from '@contexts'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ContactListTable } from '@components/Contacts'; +import createMatchMedia from '../../helpers/createMatchMedia'; + +afterEach(() => { + cleanup(); +}); const queryClient = new QueryClient(); @@ -15,6 +21,16 @@ const MockTableComponent = ({ contacts }) => ( ); +// const { getByRole } = render( +// +// +// +// +// +// +// +// ); + it('renders all clients from client context', () => { const contacts = [ { @@ -72,4 +88,12 @@ it('sorts clients by familyName', () => { const client2 = getByRole('cell', { name: 'Builder' }); expect(client1.compareDocumentPosition(client2)).toBe(Node.DOCUMENT_POSITION_PRECEDING); + + it('renders ContactsListTable when user is logged in on larger screen device', () => { + window.matchMedia = createMatchMedia(1200); + }); + + it('renders ContactsListTable when user is logged in on smaller screen device', () => { + window.matchMedia = createMatchMedia(1200); + }); }); From 5a8074768b99f10adf2a3390c3ed7b8140cf65ba Mon Sep 17 00:00:00 2001 From: Andrew Sterner Date: Thu, 6 Jun 2024 21:30:57 -0700 Subject: [PATCH 153/263] Sign in tab design --- src/components/Signup/ExistingPodForm.jsx | 14 +---- src/components/Signup/PodRegistrationForm.jsx | 27 +-------- src/pages/Signup.jsx | 56 ++++++++++++++----- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/components/Signup/ExistingPodForm.jsx b/src/components/Signup/ExistingPodForm.jsx index a11c0d98c..f2c112445 100644 --- a/src/components/Signup/ExistingPodForm.jsx +++ b/src/components/Signup/ExistingPodForm.jsx @@ -4,8 +4,7 @@ import React, { useState } from 'react'; import { useSession } from '@hooks'; // Material UI Imports import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; -import CardHeader from '@mui/material/CardHeader'; +import Box from '@mui/material/Box'; import TextField from '@mui/material/TextField'; /* Styles */ @@ -33,14 +32,7 @@ const ExistingPodForm = () => { }; return ( - - + {/* TODO: Consider changing this to Autocomplete like the NavBar and SignInModal have */} { Login to Pod Provider - +
); }; diff --git a/src/components/Signup/PodRegistrationForm.jsx b/src/components/Signup/PodRegistrationForm.jsx index 95df3786f..94ea32924 100644 --- a/src/components/Signup/PodRegistrationForm.jsx +++ b/src/components/Signup/PodRegistrationForm.jsx @@ -3,23 +3,14 @@ import React, { useState } from 'react'; import { useSearchParams } from 'react-router-dom'; // Material UI Imports import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; -import CardHeader from '@mui/material/CardHeader'; import FilledInput from '@mui/material/FilledInput'; import IconButton from '@mui/material/IconButton'; import InputAdornment from '@mui/material/InputAdornment'; import InputLabel from '@mui/material/InputLabel'; import TextField from '@mui/material/TextField'; -import Typography from '@mui/material/Typography'; +import { Box } from '@mui/material'; import { Visibility, VisibilityOff } from '@mui/icons-material'; -/* Styles for MUI components */ -const cardStyle = { - padding: '8px', - margin: '8px', - boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)' -}; - const formRowStyle = { margin: '20px 0' }; @@ -56,23 +47,11 @@ const PodRegistrationForm = ({ register, caseManagerName, previousInfo = null }) return ( <> - - Register For PASS - {searchParams.get('webId') && (

You will register with {caseManagerName ?? searchParams.get('webId')}

)} - - - +
-
+
); }; diff --git a/src/pages/Signup.jsx b/src/pages/Signup.jsx index 7512e5f9f..1c65ba7fb 100644 --- a/src/pages/Signup.jsx +++ b/src/pages/Signup.jsx @@ -10,7 +10,8 @@ import { FOAF } from '@inrupt/vocab-common-rdf'; import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; import Paper from '@mui/material/Paper'; -import { Typography } from '@mui/material'; + +import { Tab, Tabs, Typography } from '@mui/material'; // Constant Imports import { ENV } from '@constants'; // Signup Form Imports @@ -22,6 +23,38 @@ import { ExistingPodForm } from '@components/Signup'; +const PassRegistrationTab = ({ register, caseManagerName, previousInfo }) => { + const [value, setValue] = useState('1'); + + const handleChange = (_event, newValue) => { + setValue(newValue); + }; + + return ( + + + + Register + + + + + + + + + + ); +}; +/**/ /** * Signup - First screen in the user registration flow. * Allows users to either create a pod, or sign into an existing pod @@ -100,13 +133,12 @@ const Signup = () => { }, [session.info.isLoggedIn, window.location.href]); return ( - + @@ -116,19 +148,17 @@ const Signup = () => { display: 'inline-block', mx: '2px', padding: '20px', - minWidth: '400px', + minWidth: '280px', + margin: '24px', boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)' }} > {step === 'begin' && ( - <> - - - + )} {step === 'loading' && Creating Pod...} {step === 'done' && ( From a18d7c72309256f4427be7d2a3ed80f688da0168 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 10 Jun 2024 15:04:53 -0700 Subject: [PATCH 154/263] More abstraction, troubleshooting ContactProfileIcon issues --- src/components/Contacts/ContactListTable.jsx | 15 +- .../Contacts/ContactProfileIcon.jsx | 2 - src/components/NavBar/NavBar.jsx | 4 +- .../Contacts/ContactListTableDesktop.test.jsx | 0 .../Contacts/ContactListTableMobile.test.jsx | 0 .../Contacts/ContactsListTable.test.jsx | 135 +++++++++--------- test/components/NavBar/NavBar.test.jsx | 4 +- 7 files changed, 79 insertions(+), 81 deletions(-) create mode 100644 test/components/Contacts/ContactListTableDesktop.test.jsx create mode 100644 test/components/Contacts/ContactListTableMobile.test.jsx diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 0993677e2..2363d4103 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -83,8 +83,8 @@ const ContactListTable = ({ contacts, deleteContact }) => { setMessageToField(isSmallScreen ? contactId.podUrl : contactId.value.podUrl); }; - const handleProfileClick = (value) => { - console.log(value); + const handleProfileClick = (contactData) => { + ; }; const columnTitlesArray = [ @@ -187,9 +187,16 @@ const ContactListTable = ({ contacts, deleteContact }) => { Last Name - + Actions - +
{contacts?.map((contact) => ( diff --git a/src/components/Contacts/ContactProfileIcon.jsx b/src/components/Contacts/ContactProfileIcon.jsx index b965e3b52..345ea5271 100644 --- a/src/components/Contacts/ContactProfileIcon.jsx +++ b/src/components/Contacts/ContactProfileIcon.jsx @@ -35,12 +35,10 @@ const ContactProfileIcon = ({ contact }) => { // Event handler for profile page routing const handleSelectProfile = async (contactInfo) => { - console.log(`contactInfo: ${contactInfo}`); try { await getWebIdDataset(contactInfo.webId); setContact(contactInfo); } catch (error) { - console.error('Error fetching webId dataset:', error); setContact(null); navigate('/contacts'); addNotification('error', 'WebId does not exist'); diff --git a/src/components/NavBar/NavBar.jsx b/src/components/NavBar/NavBar.jsx index 06411e340..50328c550 100644 --- a/src/components/NavBar/NavBar.jsx +++ b/src/components/NavBar/NavBar.jsx @@ -12,11 +12,11 @@ import NavbarLoggedOut from './NavbarLoggedOut'; import NavbarMobile from './NavbarMobile'; /** - * NavBar Component - Component that generates proper NavBar section for PASS + * NavBar - Component that generates proper NavBar section for PASS * * @memberof NavBar * @name NavBar - * @returns {React.JSX.Element} - The Navbar component + * @returns {React.JSX.Element} The Navbar component */ const NavBar = () => { const { session } = useSession(); diff --git a/test/components/Contacts/ContactListTableDesktop.test.jsx b/test/components/Contacts/ContactListTableDesktop.test.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/test/components/Contacts/ContactListTableMobile.test.jsx b/test/components/Contacts/ContactListTableMobile.test.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/test/components/Contacts/ContactsListTable.test.jsx b/test/components/Contacts/ContactsListTable.test.jsx index 69592e8aa..d1c6dca1c 100644 --- a/test/components/Contacts/ContactsListTable.test.jsx +++ b/test/components/Contacts/ContactsListTable.test.jsx @@ -1,12 +1,13 @@ import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import { render, cleanup } from '@testing-library/react'; -import { afterEach, expect, it } from 'vitest'; +import { afterEach, describe, expect, it } from 'vitest'; // import { SessionContext } from '@contexts'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ContactListTable } from '@components/Contacts'; import createMatchMedia from '../../helpers/createMatchMedia'; +// Clear created DOM after each test afterEach(() => { cleanup(); }); @@ -21,79 +22,71 @@ const MockTableComponent = ({ contacts }) => ( ); -// const { getByRole } = render( -// -// -// -// -// -// -// -// ); - -it('renders all clients from client context', () => { - const contacts = [ - { - familyName: 'Abby', - givenName: 'Aaron', - person: 'Aaron Abby', - webId: 'https://example.com/Abby' - }, - { - familyName: 'Builder', - givenName: 'Bob', - person: 'Bob Builder', - webId: 'https://example.com/Builder' - } - ]; - - const { getAllByRole, queryByRole } = render(); - - const allRows = getAllByRole('row'); - - // Expect 3 rows: the header, Abby's row, Builder's Row - expect(allRows.length).toBe(3); - - const row1GivenName = queryByRole('cell', { name: 'Aaron' }); - const row1FamilyName = queryByRole('cell', { name: 'Abby' }); - - const row2GivenName = queryByRole('cell', { name: 'Bob' }); - const row2FamilyName = queryByRole('cell', { name: 'Builder' }); - - expect(row1GivenName).not.toBeNull(); - expect(row1FamilyName).not.toBeNull(); - expect(row2GivenName).not.toBeNull(); - expect(row2FamilyName).not.toBeNull(); -}); +describe('contacts table tests', () => { + it('renders all clients from client context', () => { + const contacts = [ + { + familyName: 'Abby', + givenName: 'Aaron', + person: 'Aaron Abby', + webId: 'https://example.com/Abby' + }, + { + familyName: 'Builder', + givenName: 'Bob', + person: 'Bob Builder', + webId: 'https://example.com/Builder' + } + ]; + + const { getAllByRole, queryByRole } = render(); + + const allRows = getAllByRole('row'); + + // Expect 3 rows: the header, Abby's row, Builder's Row + expect(allRows.length).toBe(3); + + const row1GivenName = queryByRole('cell', { name: 'Aaron' }); + const row1FamilyName = queryByRole('cell', { name: 'Abby' }); + + const row2GivenName = queryByRole('cell', { name: 'Bob' }); + const row2FamilyName = queryByRole('cell', { name: 'Builder' }); + + expect(row1GivenName).not.toBeNull(); + expect(row1FamilyName).not.toBeNull(); + expect(row2GivenName).not.toBeNull(); + expect(row2FamilyName).not.toBeNull(); + }); -it('sorts clients by familyName', () => { - const originalArray = [ - { - familyName: 'Zeigler', - givenName: 'Aaron', - person: 'Aaron Zeigler', - webId: 'https://example.com/Zeigler' - }, - { - familyName: 'Builder', - givenName: 'Bob', - person: 'Bob Builder', - webId: 'https://example.com/Builder' - } - ]; - - const { getByRole } = render(); - - const client1 = getByRole('cell', { name: 'Zeigler' }); - const client2 = getByRole('cell', { name: 'Builder' }); - - expect(client1.compareDocumentPosition(client2)).toBe(Node.DOCUMENT_POSITION_PRECEDING); - - it('renders ContactsListTable when user is logged in on larger screen device', () => { - window.matchMedia = createMatchMedia(1200); + it('sorts clients by familyName', () => { + const originalArray = [ + { + familyName: 'Zeigler', + givenName: 'Aaron', + person: 'Aaron Zeigler', + webId: 'https://example.com/Zeigler' + }, + { + familyName: 'Builder', + givenName: 'Bob', + person: 'Bob Builder', + webId: 'https://example.com/Builder' + } + ]; + + const { getByRole } = render(); + + const client1 = getByRole('cell', { name: 'Zeigler' }); + const client2 = getByRole('cell', { name: 'Builder' }); + + expect(client1.compareDocumentPosition(client2)).toBe(Node.DOCUMENT_POSITION_PRECEDING); }); - it('renders ContactsListTable when user is logged in on smaller screen device', () => { + it('renders ContactsListTableDesktop when user is logged in on larger screen device', () => { window.matchMedia = createMatchMedia(1200); }); + + it('renders ContactsListTableMobile when user is logged in on smaller screen device', () => { + window.matchMedia = createMatchMedia(500); + }); }); diff --git a/test/components/NavBar/NavBar.test.jsx b/test/components/NavBar/NavBar.test.jsx index 8ed0658a0..f7fc1ccb8 100644 --- a/test/components/NavBar/NavBar.test.jsx +++ b/test/components/NavBar/NavBar.test.jsx @@ -1,13 +1,13 @@ import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import { render, cleanup } from '@testing-library/react'; -import { expect, it, afterEach, describe } from 'vitest'; +import { afterEach, describe, expect, it } from 'vitest'; import { SessionContext } from '@contexts'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import NavBar from '../../../src/components/NavBar/NavBar'; import createMatchMedia from '../../helpers/createMatchMedia'; -// clear created dom after each test, to start fresh for next +// Clear created DOM after each test afterEach(() => { cleanup(); }); From 6cd6dcb48a06bca66ef9b4212f0c01a2edd2f583 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 10 Jun 2024 20:53:24 -0700 Subject: [PATCH 155/263] Refactoring Menu into Tabs --- src/pages/CivicProfile.jsx | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/pages/CivicProfile.jsx b/src/pages/CivicProfile.jsx index 1d152494d..cea17ba5e 100644 --- a/src/pages/CivicProfile.jsx +++ b/src/pages/CivicProfile.jsx @@ -4,8 +4,8 @@ import { Link, Outlet, useLocation } from 'react-router-dom'; // Material UI Imports import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; -import MenuItem from '@mui/material/MenuItem'; -import MenuList from '@mui/material/MenuList'; +import Tab from '@mui/material/Tab'; +import Tabs from '@mui/material/Tabs'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/system'; // Component Imports @@ -27,18 +27,25 @@ const CivicProfile = () => { const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); return ( - - + + From 649bd1f45c76c52d2925bf2d420c2bb654c4599c Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 10 Jun 2024 21:18:32 -0700 Subject: [PATCH 156/263] Refactoring forms --- .../CivicProfileForms/BasicInfo.jsx | 2 +- .../CivicProfileForms/FinancialInfo.jsx | 7 +- .../CivicProfileForms/HousingInfo.jsx | 210 +++++++++--------- src/pages/CivicProfile.jsx | 14 +- 4 files changed, 125 insertions(+), 108 deletions(-) diff --git a/src/components/CivicProfileForms/BasicInfo.jsx b/src/components/CivicProfileForms/BasicInfo.jsx index 2766fb1d8..8eb2f3dec 100644 --- a/src/components/CivicProfileForms/BasicInfo.jsx +++ b/src/components/CivicProfileForms/BasicInfo.jsx @@ -16,7 +16,7 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; // Dependency Imports import dayjs from 'dayjs'; -// Hooks Imports +// Custom Hooks Imports import { useCivicProfile, useNotification } from '@hooks'; // Component Imports import { FormSection } from '../Form'; diff --git a/src/components/CivicProfileForms/FinancialInfo.jsx b/src/components/CivicProfileForms/FinancialInfo.jsx index 0f9d84d20..b115e4c33 100644 --- a/src/components/CivicProfileForms/FinancialInfo.jsx +++ b/src/components/CivicProfileForms/FinancialInfo.jsx @@ -2,7 +2,12 @@ import React from 'react'; // Material UI Imports import Typography from '@mui/material/Typography'; +import { FormSection } from '../Form'; -const FinancialInfo = () => Financial Info; +const FinancialInfo = () => ( + + To be completed + +); export default FinancialInfo; diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 16ed812ab..11af7557f 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -1,17 +1,18 @@ // React Imports -import React, { useState, useEffect } from 'react'; -// MUI Imports +import React, { useEffect, useState } from 'react'; +// Material UI Imports +import Button from '@mui/material/Button'; +import CheckIcon from '@mui/icons-material/Check'; +import ClearIcon from '@mui/icons-material/Clear'; import FormControl from '@mui/material/FormControl'; import Grid from '@mui/material/Grid'; -import TextField from '@mui/material/TextField'; -import Select from '@mui/material/Select'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; -import Button from '@mui/material/Button'; -import CheckIcon from '@mui/icons-material/Check'; -import ClearIcon from '@mui/icons-material/Clear'; +import Select from '@mui/material/Select'; +import TextField from '@mui/material/TextField'; // Custom Hooks Imports import { useCivicProfile, useNotification } from '@hooks'; +// Component Imports import { FormSection } from '../Form'; /** @@ -90,38 +91,44 @@ const HousingInfo = () => { return ( - - - +
+ + + + + + + + { value={formData.lastPermanentZIP ?? ''} error={zipError} helperText={zipError ? 'Invalid ZIP format. Expected: 12345 or 12345-6789' : ''} + fullWidth /> - + + + + + Months Houseless Past 3 Years: + + + + + + + + Number of Times Houseless Past 3 Years: + + + + + + + + Time Until Loss of Housing: + + + + - - - Months Houseless Past 3 Years: - - - - - Number of Times Houseless Past 3 Years: - - - - - - Time Until Loss of Housing: - - - - - - + + - - - - + + - + - +
); }; diff --git a/src/pages/CivicProfile.jsx b/src/pages/CivicProfile.jsx index cea17ba5e..deb33cf15 100644 --- a/src/pages/CivicProfile.jsx +++ b/src/pages/CivicProfile.jsx @@ -6,8 +6,8 @@ import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; import Tab from '@mui/material/Tab'; import Tabs from '@mui/material/Tabs'; -import useMediaQuery from '@mui/material/useMediaQuery'; -import { useTheme } from '@mui/system'; +// import useMediaQuery from '@mui/material/useMediaQuery'; +// import { useTheme } from '@mui/system'; // Component Imports import { CIVIC_FORM_LIST } from '@components/CivicProfileForms'; @@ -23,8 +23,8 @@ const CivicProfile = () => { localStorage.setItem('restorePath', location.pathname); const currentForm = location.pathname.split('/').pop(); - const theme = useTheme(); - const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + // const theme = useTheme(); + // const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); return ( @@ -32,7 +32,7 @@ const CivicProfile = () => {
- + - +
); }; From f5d83e1ea803c73a28cbf39e32bcf6cb8031fa0c Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 11 Jun 2024 20:15:30 -0700 Subject: [PATCH 157/263] Renaming test file --- ...ntactsListTable.test.jsx => ContactListTable.test.jsx} | 0 test/components/Contacts/ContactListTableDesktop.test.jsx | 8 ++++++++ test/components/Contacts/ContactListTableMobile.test.jsx | 8 ++++++++ 3 files changed, 16 insertions(+) rename test/components/Contacts/{ContactsListTable.test.jsx => ContactListTable.test.jsx} (100%) diff --git a/test/components/Contacts/ContactsListTable.test.jsx b/test/components/Contacts/ContactListTable.test.jsx similarity index 100% rename from test/components/Contacts/ContactsListTable.test.jsx rename to test/components/Contacts/ContactListTable.test.jsx diff --git a/test/components/Contacts/ContactListTableDesktop.test.jsx b/test/components/Contacts/ContactListTableDesktop.test.jsx index e69de29bb..39fa2a972 100644 --- a/test/components/Contacts/ContactListTableDesktop.test.jsx +++ b/test/components/Contacts/ContactListTableDesktop.test.jsx @@ -0,0 +1,8 @@ +// import React from 'react'; +// import { BrowserRouter } from 'react-router-dom'; +// import { render } from '@testing-library/react'; +// import { expect, it } from 'vitest'; +// import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +// import ContactListTableDesktop from '../../../src/components/Contacts/ContactListTableDesktop'; + +// const queryClient = new QueryClient(); diff --git a/test/components/Contacts/ContactListTableMobile.test.jsx b/test/components/Contacts/ContactListTableMobile.test.jsx index e69de29bb..528e30eb1 100644 --- a/test/components/Contacts/ContactListTableMobile.test.jsx +++ b/test/components/Contacts/ContactListTableMobile.test.jsx @@ -0,0 +1,8 @@ +// import React from 'react'; +// import { BrowserRouter } from 'react-router-dom'; +// import { render } from '@testing-library/react'; +// import { expect, it } from 'vitest'; +// import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +// import ContactListTableMobile from '../../../src/components/Contacts/ContactListTableMobile'; + +// const queryClient = new QueryClient(); From 51a21bdfff616aa9d35f75fdb31e5b8e86d0dbb5 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 11 Jun 2024 20:21:58 -0700 Subject: [PATCH 158/263] Refactoring Contacts columns --- src/components/Contacts/ContactListTable.jsx | 37 ++++++-------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 2363d4103..969926a2a 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -7,7 +7,6 @@ import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; -import Grid from '@mui/material/Grid'; import IconButton from '@mui/material/IconButton'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; @@ -180,13 +179,8 @@ const ContactListTable = ({ contacts, deleteContact }) => { position: 'relative' }} > - - - First Name - - - Last Name - + + Name { > Actions - + {contacts?.map((contact) => ( @@ -208,22 +202,13 @@ const ContactListTable = ({ contacts, deleteContact }) => { }} > - - - - {contact.givenName || ''} - - - - - {contact.familyName || ''} - - - - - {contact.webId} - - + + + {contact.givenName || ''} {contact.familyName || ''} + + + {contact.webId} + { - + Date: Tue, 11 Jun 2024 23:22:08 -0700 Subject: [PATCH 159/263] Abstracting code to ContactListTableDesktop --- src/components/Contacts/ContactListTable.jsx | 120 ++----------------- 1 file changed, 7 insertions(+), 113 deletions(-) diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 969926a2a..1aa9e5b56 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -15,13 +15,6 @@ import SendIcon from '@mui/icons-material/Send'; import Typography from '@mui/material/Typography'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; -import { - DataGrid, - GridToolbarContainer, - GridActionsCellItem, - GridToolbarFilterButton, - GridToolbarDensitySelector -} from '@mui/x-data-grid'; // Custom Hooks Imports import useNotification from '@hooks/useNotification'; // Util Imports @@ -29,16 +22,9 @@ import { saveToClipboard } from '@utils'; // Component Imports import ContactProfileIcon from './ContactProfileIcon'; import { NewMessageModal } from '../Modals'; -// import ContactListTableDesktop from './ContactListTableDesktop' +import ContactListTableDesktop from './ContactListTableDesktop'; // import ContactListTableMobile from './ContactListTableMobile' -const CustomToolbar = () => ( - - - - -); - /** * @typedef {import("../../typedefs.js").userListObject} userListObject */ @@ -86,70 +72,6 @@ const ContactListTable = ({ contacts, deleteContact }) => { ; }; - const columnTitlesArray = [ - { - field: 'First Name', - minWidth: 120, - flex: 1, - headerAlign: 'center', - align: 'center' - }, - { - field: 'Last Name', - minWidth: 120, - flex: 1, - headerAlign: 'center', - align: 'center' - }, - { - field: 'webId', - headerName: 'Web ID', - minWidth: 150, - flex: 1, - headerAlign: 'center', - align: 'center' - }, - { - field: 'Profile', - renderCell: (contactData) => ( - - // handleProfileClick(contactData)} /> - ), - sortable: false, - filterable: false, - width: 80, - headerAlign: 'center', - align: 'center' - }, - { - field: 'Message', - renderCell: (contactId) => ( - handleSendMessage(contactId)} - /> - ), - sortable: false, - filterable: false, - width: 80, - headerAlign: 'center', - align: 'center' - }, - { - field: 'actions', - type: 'actions', - headerName: 'Delete', - width: 80, - getActions: (contactData) => [ - } - onClick={() => deleteContact(contactData.row.Delete)} - label="Delete" - /> - ] - } - ]; - const iconSize = { height: '24px', width: '24px' @@ -290,43 +212,15 @@ const ContactListTable = ({ contacts, deleteContact }) => { + // ))} ) : ( - ({ - id: contact.webId, - 'First Name': contact.givenName || '', - 'Last Name': contact.familyName || '', - webId: contact.webId, - Profile: contact, - Message: contact, - Delete: contact - }))} - slots={{ - toolbar: CustomToolbar - }} - sx={{ - '.MuiDataGrid-columnHeader': { - background: theme.palette.primary.light, - color: '#fff' - }, - '.MuiDataGrid-columnSeparator': { - display: 'none' - } - }} - pageSizeOptions={[10]} - initialState={{ - pagination: { - paginationModel: { pageSize: 10, page: 0 } - }, - sorting: { - sortModel: [{ field: 'webId', sort: 'asc' }] - } - }} - disableColumnMenu - disableRowSelectionOnClick + )} Date: Thu, 13 Jun 2024 13:24:10 -0700 Subject: [PATCH 160/263] Abstracting code to ContactListTableMobile --- src/components/Contacts/ContactListTable.jsx | 178 +----------------- .../Contacts/ContactListTableMobile.jsx | 169 +++++++++++++++-- 2 files changed, 161 insertions(+), 186 deletions(-) diff --git a/src/components/Contacts/ContactListTable.jsx b/src/components/Contacts/ContactListTable.jsx index 1aa9e5b56..93342e69b 100644 --- a/src/components/Contacts/ContactListTable.jsx +++ b/src/components/Contacts/ContactListTable.jsx @@ -2,28 +2,12 @@ import React, { useState } from 'react'; // Material UI Imports import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; -import CardContent from '@mui/material/CardContent'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'; -import IconButton from '@mui/material/IconButton'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; -import MoreVertIcon from '@mui/icons-material/MoreVert'; -import SendIcon from '@mui/icons-material/Send'; -import Typography from '@mui/material/Typography'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useTheme } from '@mui/material/styles'; -// Custom Hooks Imports -import useNotification from '@hooks/useNotification'; -// Util Imports -import { saveToClipboard } from '@utils'; // Component Imports -import ContactProfileIcon from './ContactProfileIcon'; import { NewMessageModal } from '../Modals'; import ContactListTableDesktop from './ContactListTableDesktop'; -// import ContactListTableMobile from './ContactListTableMobile' +import ContactListTableMobile from './ContactListTableMobile'; /** * @typedef {import("../../typedefs.js").userListObject} userListObject @@ -43,44 +27,14 @@ import ContactListTableDesktop from './ContactListTableDesktop'; const ContactListTable = ({ contacts, deleteContact }) => { const [showMessageModal, setShowMessageModal] = useState(false); const [messageToField, setMessageToField] = useState(''); - const { addNotification } = useNotification(); - const [anchorEl, setAnchorEl] = useState(null); - const [openMenu, setOpenMenu] = useState(null); const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); - const handleClick = (event, contact) => { - setAnchorEl(event.currentTarget); - setOpenMenu(contact.webId); - }; - const handleClose = () => { - setAnchorEl(null); - setOpenMenu(null); - }; - - const handleMenuItemClick = (action, contact) => () => { - action(contact); - handleClose(); - }; - const handleSendMessage = (contactId) => { setShowMessageModal(!showMessageModal); setMessageToField(isSmallScreen ? contactId.podUrl : contactId.value.podUrl); }; - const handleProfileClick = (contactData) => { - ; - }; - - const iconSize = { - height: '24px', - width: '24px' - }; - - const iconStyling = { - width: '100%' - }; - return ( { }} > {isSmallScreen ? ( - - - - Name - - Actions - - - - {contacts?.map((contact) => ( - - - - - - {contact.givenName || ''} {contact.familyName || ''} - - - {contact.webId} - - - handleClick(event, contact)} - > - - - - - - - - - saveToClipboard( - contact.webId, - 'webId copied to clipboard', - addNotification - ), - contact - )} - startIcon={} - sx={iconStyling} - > - Copy WebId - - } - sx={iconStyling} - > - Profile - - - } - sx={iconStyling} - > - Message - - } - sx={iconStyling} - > - Delete - - - - - // - ))} - + ) : ( { - return
ContactListTableMobile
; +const ContactListTableMobile = ({ contacts, deleteContact, handleSendMessage }) => { + const { addNotification } = useNotification(); + const [anchorEl, setAnchorEl] = useState(null); + const [openMenu, setOpenMenu] = useState(null); + const theme = useTheme(); + + const handleClick = (event, contact) => { + setAnchorEl(event.currentTarget); + setOpenMenu(contact.webId); + }; + const handleClose = () => { + setAnchorEl(null); + setOpenMenu(null); + }; + + const handleMenuItemClick = (action, contact) => () => { + action(contact); + handleClose(); + }; + + const handleProfileClick = (contactData) => { + ; + }; + + const iconSize = { + height: '24px', + width: '24px' + }; + + const iconStyling = { + width: '100%' + }; + + return ( + + + + Name + + Actions + + + + {contacts?.map((contact) => ( + + + + + + {contact.givenName || ''} {contact.familyName || ''} + + + {contact.webId} + + + handleClick(event, contact)} + > + + + + + + + + + saveToClipboard(contact.webId, 'webId copied to clipboard', addNotification), + contact + )} + startIcon={} + sx={iconStyling} + > + Copy WebId + + } + sx={iconStyling} + > + Profile + + + } + sx={iconStyling} + > + Message + + } + sx={iconStyling} + > + Delete + + + + + ))} + + ); }; export default ContactListTableMobile; From 336d4792308694ec220272771d64b38a71129e48 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 13 Jun 2024 13:26:43 -0700 Subject: [PATCH 161/263] Adding JSDocs --- .../Contacts/ContactListTableMobile.jsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/Contacts/ContactListTableMobile.jsx b/src/components/Contacts/ContactListTableMobile.jsx index 3b06c89e7..48a58aef6 100644 --- a/src/components/Contacts/ContactListTableMobile.jsx +++ b/src/components/Contacts/ContactListTableMobile.jsx @@ -21,7 +21,24 @@ import { saveToClipboard } from '@utils'; // Component Imports import ContactProfileIcon from './ContactProfileIcon'; -// JSDocs +/** + * @typedef {object} Contact + * @property {string} webId - The Web ID of the contact + * @property {string} givenName - The given name of the contact + * @property {string} familyName - The family name of the contact + */ + +/** + * ContactListTableMobile - Component for displaying contacts in a DataGrid + * + * @memberof Contacts + * @name ContactListTableMobile + * @param {object} Props - The props for ContactListTableMobile + * @param {Contact[]} Props.contacts - The list of contacts to display + * @param {Function} Props.deleteContact - Function to delete a contact + * @param {Function} Props.handleSendMessage - Function to handle sending a message + * @returns {React.JSX.Element} The ContactListTableMobile component + */ const ContactListTableMobile = ({ contacts, deleteContact, handleSendMessage }) => { const { addNotification } = useNotification(); const [anchorEl, setAnchorEl] = useState(null); From c345c5bca207b5b1aba58bb171ef25d6094432a2 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 14 Jun 2024 17:52:56 -0700 Subject: [PATCH 162/263] Styling updates. Disabling navigation to incomplete form. --- src/AppRoutes.jsx | 1 + .../CivicProfileForms/BasicInfo.jsx | 10 +++--- .../CivicProfileForms/FormLayout.jsx | 34 ++++++++++++++----- .../CivicProfileForms/HousingInfo.jsx | 29 ++++++---------- src/components/Modals/AddContactModal.jsx | 26 ++++++-------- src/pages/CivicProfile.jsx | 13 ++++--- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/AppRoutes.jsx b/src/AppRoutes.jsx index 4d8afe1ec..f933af398 100644 --- a/src/AppRoutes.jsx +++ b/src/AppRoutes.jsx @@ -53,6 +53,7 @@ const AppRoutes = () => { ))} } /> + {/* TODO: Remove blank Civic Profile page, ensure it directs Basic Information instead */} }> {CIVIC_FORM_LIST.map((formProps) => ( { return (
- + { - + + + - + ) : ( )} {pageIdx < HMIS_FORM_LIST.length - 1 ? ( - - Next > - + ) : ( )} diff --git a/src/components/CivicProfileForms/HousingInfo.jsx b/src/components/CivicProfileForms/HousingInfo.jsx index 11af7557f..9cb366114 100644 --- a/src/components/CivicProfileForms/HousingInfo.jsx +++ b/src/components/CivicProfileForms/HousingInfo.jsx @@ -22,7 +22,6 @@ import { FormSection } from '../Form'; * @name HousingInfo * @returns {React.JSX.Element} The HousingInfo Component */ - const HousingInfo = () => { const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); const { addNotification } = useNotification(); @@ -92,14 +91,10 @@ const HousingInfo = () => { return ( - + { { { { Months Houseless Past 3 Years: { Time Until Loss of Housing: Date: Wed, 26 Jun 2024 11:01:43 -0700 Subject: [PATCH 172/263] Updating tab orientation --- src/pages/CivicProfile.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/CivicProfile.jsx b/src/pages/CivicProfile.jsx index b69cc3383..a2819ac1a 100644 --- a/src/pages/CivicProfile.jsx +++ b/src/pages/CivicProfile.jsx @@ -37,10 +37,9 @@ const CivicProfile = () => { >