From 0b39075e7df530ec4e90f70eeb7368252002637a Mon Sep 17 00:00:00 2001 From: suaniii Date: Fri, 7 Feb 2025 23:54:43 -0800 Subject: [PATCH 01/49] fix hyperlink --- .../UserProfile/TeamsAndProjects/UserProjectsTable.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx b/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx index ac0093c3d0..9ecabd7c74 100644 --- a/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx +++ b/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx @@ -277,7 +277,9 @@ const UserProjectsTable = React.memo(props => { {project.projectName}
- {task.taskName && `\u2003 ↳ ${task.taskName}`} + + {task.taskName && `\u2003 ↳ ${task.taskName}`} + {!isCompletedTask && props.edit && props.role && canDeleteTasks && ( From 32ba5bea4aabbe56eeda1c04a3384e7e4288d273 Mon Sep 17 00:00:00 2001 From: suaniii Date: Sat, 8 Feb 2025 00:03:16 -0800 Subject: [PATCH 02/49] fix --- .../UserProfile/TeamsAndProjects/UserProjectsTable.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx b/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx index 9ecabd7c74..09e1afb728 100644 --- a/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx +++ b/src/components/UserProfile/TeamsAndProjects/UserProjectsTable.jsx @@ -277,9 +277,9 @@ const UserProjectsTable = React.memo(props => { {project.projectName}
- + {task.taskName && `\u2003 ↳ ${task.taskName}`} - + {!isCompletedTask && props.edit && props.role && canDeleteTasks && ( From 4890555c15a7f1e1b5d2ddd0cc923b522c120431 Mon Sep 17 00:00:00 2001 From: Aureliano Maximus Date: Wed, 26 Feb 2025 04:28:00 -0600 Subject: [PATCH 03/49] Added regex to filter if timelog notes has correct link format --- src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx index ec0e1382f1..5cf1d18a6d 100644 --- a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx +++ b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx @@ -230,7 +230,14 @@ function TimeEntryForm(props) { const handleEditorChange = (content, editor) => { const { wordcount } = editor.plugins; - const hasLink = content.indexOf('http://') > -1 || content.indexOf('https://') > -1; + // const hasLink = content.indexOf('http://') > -1 || content.indexOf('https://') > -1; + // Starts with "https://" + // Negative lookahead to exclude "www.dropbox.com/home" + // Followed by any subdomain and domain + // Optionally followed by any path + // Case insensitive + const regex = /^https:\/\/(?!www\.dropbox\.com\/home)[\w.-]+\.[\w.-]+\.com(\/\S*)?$/i; + const hasLink = regex.test(content); const enoughWords = wordcount.body.getWordCount() > 10; setFormValues(fv => ({ ...fv, [editor.id]: content })); setReminder(r => ({ From 8cc2d463b447323d4d9860e1619b92dfbc9a73da Mon Sep 17 00:00:00 2001 From: AurelianoMaximus Date: Wed, 26 Feb 2025 17:43:41 -0600 Subject: [PATCH 04/49] updated regex to better filter dropbox share link --- src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx index 5cf1d18a6d..bda14a463d 100644 --- a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx +++ b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx @@ -230,14 +230,8 @@ function TimeEntryForm(props) { const handleEditorChange = (content, editor) => { const { wordcount } = editor.plugins; - // const hasLink = content.indexOf('http://') > -1 || content.indexOf('https://') > -1; - // Starts with "https://" - // Negative lookahead to exclude "www.dropbox.com/home" - // Followed by any subdomain and domain - // Optionally followed by any path - // Case insensitive - const regex = /^https:\/\/(?!www\.dropbox\.com\/home)[\w.-]+\.[\w.-]+\.com(\/\S*)?$/i; - const hasLink = regex.test(content); + const regexFilter = /https:\/\/(?!.*dropbox\.com\/home).*$/i; + const hasLink = regexFilter.test(content) && !/https:\/\/.*dropbox\.com\/home/.test(content); const enoughWords = wordcount.body.getWordCount() > 10; setFormValues(fv => ({ ...fv, [editor.id]: content })); setReminder(r => ({ From db318ecec589d59c856baf36fc873e54e2522298 Mon Sep 17 00:00:00 2001 From: AurHubertMax Date: Mon, 3 Mar 2025 20:28:36 -0600 Subject: [PATCH 05/49] Updated regex in TimeEntryForm to better exclude localhost and specific Dropbox URLs from link validation --- src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx index bda14a463d..a5cbe11552 100644 --- a/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx +++ b/src/components/Timelog/TimeEntryForm/TimeEntryForm.jsx @@ -230,8 +230,8 @@ function TimeEntryForm(props) { const handleEditorChange = (content, editor) => { const { wordcount } = editor.plugins; - const regexFilter = /https:\/\/(?!.*dropbox\.com\/home).*$/i; - const hasLink = regexFilter.test(content) && !/https:\/\/.*dropbox\.com\/home/.test(content); + const regexFilter = /https:\/\/(?!(www\.)?localhost|(www\.)?dropbox\.com(?!\/scl\/)|(www\.)?[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/gim; + const hasLink = regexFilter.test(content); const enoughWords = wordcount.body.getWordCount() > 10; setFormValues(fv => ({ ...fv, [editor.id]: content })); setReminder(r => ({ From b04603c08658112e7218d3faabd2e23b745c454b Mon Sep 17 00:00:00 2001 From: suaniii Date: Fri, 7 Mar 2025 23:30:50 -0800 Subject: [PATCH 06/49] unit test --- .../__tests__/FormattedReport.test.js | 162 +++++++++++++++++- 1 file changed, 156 insertions(+), 6 deletions(-) diff --git a/src/components/WeeklySummariesReport/__tests__/FormattedReport.test.js b/src/components/WeeklySummariesReport/__tests__/FormattedReport.test.js index 4d13441d22..5e54efa2e8 100644 --- a/src/components/WeeklySummariesReport/__tests__/FormattedReport.test.js +++ b/src/components/WeeklySummariesReport/__tests__/FormattedReport.test.js @@ -1,12 +1,162 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; -import mockSummaries from '../__mocks__/weeklySummariesReportData'; // Located in the tested component's __mocks__ folder +import { Provider } from 'react-redux'; +import { createStore, applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import { MemoryRouter } from 'react-router-dom'; import FormattedReport from '../FormattedReport'; +import moment from 'moment'; +import '@testing-library/jest-dom/extend-expect'; + +jest.mock('../../../utils/permissions', () => ({ + __esModule: true, + default: () => () => true, + cantUpdateDevAdminDetails: () => false, +})); + +jest.mock('actions/weeklySummariesReport', () => ({ + updateOneSummaryReport: () => () => Promise.resolve({ status: 200 }), +})); + +jest.mock('components/UserProfile/EditableModal/RoleInfoModal', () => () => ( +
RoleInfoModal
+)); + +jest.mock('axios', () => ({ + patch: jest.fn(() => Promise.resolve({ status: 200 })), +})); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + }, +})); + +const initialState = { theme: { darkMode: false } }; +const store = createStore(state => state, initialState, applyMiddleware(thunk)); + +const dummySummary = { + _id: '1', + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + totalSeconds: [3600], + promisedHoursByWeek: [2], + weeklySummaries: [ + { + summary: '

Test summary

', + uploadDate: moment().toISOString(), + }, + ], + weeklySummariesCount: '5', + teamCode: 'ABC123', + mediaUrl: 'http://example.com/media', + adminLinks: [{ Name: 'Media Folder', Link: 'http://example.com/folder' }], + badgeCollection: [], + timeOffFrom: moment() + .subtract(1, 'days') + .format(), + timeOffTill: moment() + .add(1, 'days') + .format(), + totalTangibleHrs: 100, + daysInTeam: 70, + bioPosted: 'default', + weeklySummaryOption: 'Default', +}; + +const dummyAuthAdmin = { + user: { + email: 'admin@example.com', + role: 'Administrator', + }, +}; + +const defaultProps = { + summaries: [dummySummary], + weekIndex: 0, + bioCanEdit: true, + allRoleInfo: [], + badges: [], + loadBadges: false, + canEditTeamCode: true, + auth: dummyAuthAdmin, + canSeeBioHighlight: true, + handleTeamCodeChange: jest.fn(), + handleSpecialColorDotClick: jest.fn(), +}; + +describe('FormattedReport minimal test', () => { + it('renders without crashing', () => { + render( + + + + + , + ); + expect(screen.getByText(/John Doe/)).toBeInTheDocument(); + expect(screen.getByText('Test summary')).toBeInTheDocument(); + }); + + it('does not render the Emails section for non-admin users', () => { + const nonAdminAuth = { user: { email: 'user@example.com', role: 'Volunteer' } }; + const props = { ...defaultProps, auth: nonAdminAuth }; + render( + + + + + , + ); + expect(screen.queryByText('Emails')).toBeNull(); + }); + + it('renders fallback text when weekly summary text is missing', () => { + const summaryNoText = { + ...dummySummary, + weeklySummaries: [{}], // Missing the 'summary' property. + weeklySummaryOption: 'Default', + }; + const props = { ...defaultProps, summaries: [summaryNoText] }; + render( + + + + + , + ); + expect(screen.getByText(/Not provided!/)).toBeInTheDocument(); + }); + + it('renders media URL link using adminLinks when mediaUrl is not provided', () => { + const summaryNoMedia = { + ...dummySummary, + mediaUrl: null, + }; + const props = { ...defaultProps, summaries: [summaryNoMedia] }; + render( + + + + + , + ); + const mediaLink = screen.getByText(/Open link to media files/); + expect(mediaLink).toBeInTheDocument(); + expect(mediaLink).toHaveAttribute('href', 'http://example.com/folder'); + }); -describe('FormattedReport Component', () => { - it('Snapshot with mocked data', () => { - //const { asFragment } = render(); - // expect(asFragment()).toMatchSnapshot(); + it('displays team code as text when editing is disabled', () => { + const props = { ...defaultProps, canEditTeamCode: false }; + render( + + + + + , + ); + expect(screen.queryByPlaceholderText('X-XXX')).toBeNull(); + expect(screen.getByText('ABC123')).toBeInTheDocument(); }); }); From 0922fe7c5b625605dae794a1271c796ff9e36ae7 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Fri, 14 Mar 2025 08:43:53 -0400 Subject: [PATCH 07/49] feat: WIP added functionality to aknowledge the new permission added --- src/components/Dashboard/Dashboard.jsx | 39 +++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index 7d053a5394..b2d7810e24 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -15,15 +15,21 @@ import { DEV_ADMIN_ACCOUNT_CUSTOM_WARNING_MESSAGE_DEV_ENV_ONLY, PROTECTED_ACCOUNT_MODIFICATION_WARNING_MESSAGE, } from 'utils/constants'; +import { ENDPOINTS } from 'utils/URL'; +import axios from 'axios'; +import { getUserProfile, updateUserProfile } from 'actions/userProfile'; export function Dashboard(props) { const [popup, setPopup] = useState(false); const [filteredUserTeamIds, setFilteredUserTeamIds] = useState([]); const [summaryBarData, setSummaryBarData] = useState(null); - const {match, authUser} = props; + const { match, authUser, displayUserProfile } = props; + const { permissions, _id: userId } = displayUserProfile || {}; const checkSessionStorage = () => JSON.parse(sessionStorage.getItem('viewingUser')) ?? false; const [viewingUser, setViewingUser] = useState(checkSessionStorage); - const [displayUserId, setDisplayUserId] = useState(match.params.userId || viewingUser?.userId || authUser.userid); + const [displayUserId, setDisplayUserId] = useState( + match.params.userId || viewingUser?.userId || authUser.userid, + ); const isNotAllowedToEdit = cantUpdateDevAdminDetails(viewingUser?.email, authUser.email); const darkMode = useSelector(state => state.theme.darkMode); @@ -61,6 +67,20 @@ export function Dashboard(props) { }; }, []); + const updateAcknow = async () => { + try { + const res = await axios.put(ENDPOINTS.USER_PROFILE(userId), { + _id: userId, + isAcknowledged: true, + }); + // console.log('response', res); + if (res.status == 200) { + props.getUserProfile(userId); + } + } catch (e) { + console.log('update ack', e); + } + }; return ( - + {!permissions?.isAcknowledged ? ( + + ) : null} @@ -136,4 +160,11 @@ const mapStateToProps = state => ({ displayUserProfile: state.userProfile, }); -export default connect(mapStateToProps)(Dashboard); +const mapDispatchToProps = dispatch => { + return { + updateUserProfile: data => updateUserProfile(data)(dispatch), + getUserProfile: userId => getUserProfile(userId)(dispatch), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); From ebbe2e6fa7dca93d7b9e656ce490dacdf0348f71 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Tue, 18 Mar 2025 22:15:21 -0400 Subject: [PATCH 08/49] feat: added popup for notifying permission change --- src/components/Header/Header.jsx | 25 ++++++++++++++++++++++++- src/components/PopUpBar/PopUpBar.jsx | 5 ++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index d2fdb21486..0c0fa69f5a 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -214,6 +214,22 @@ export function Header(props) { const openModal = () => { setLogoutPopup(true); }; + + const handlePermissionChangeAck = async() => { + // handle setting the ack true + try { + const res = await axios.put(ENDPOINTS.USER_PROFILE(userId), { + _id: userId, + isAcknowledged: true, + }); + // console.log('response', res); + if (res.status === 200) { + props.getUserProfile(userId); + } + } catch (e) { + console.log('update ack', e); + } + } const removeViewingUser = () => { setPopup(false); @@ -302,6 +318,7 @@ export function Header(props) { if (location.pathname === '/login') return null; + const viewingUser = JSON.parse(window.sessionStorage.getItem('viewingUser')) return (
@@ -561,8 +578,14 @@ export function Header(props) { {!isAuthUser && ( setPopup(prevPopup => !prevPopup)} - viewingUser={JSON.parse(window.sessionStorage.getItem('viewingUser'))} + /> + )} + {props.auth.isAuthenticated && !props.userProfile?.permissions?.isAcknowledged && ( + handlePermissionChangeAck} /> )}
diff --git a/src/components/PopUpBar/PopUpBar.jsx b/src/components/PopUpBar/PopUpBar.jsx index 684583a016..fe4e1ca377 100644 --- a/src/components/PopUpBar/PopUpBar.jsx +++ b/src/components/PopUpBar/PopUpBar.jsx @@ -2,11 +2,10 @@ import './PopUpBar.css'; function PopUpBar(props) { - const { viewingUser, onClickClose } = props; - const { firstName, lastName } = viewingUser; + const { message, onClickClose } = props; return (
- {`You are currently viewing the header for ${firstName} ${lastName}`} + {message} From 1e717be5b9f42464b479cf31e9ae6cdd129eabbb Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Tue, 18 Mar 2025 22:15:39 -0400 Subject: [PATCH 09/49] Revert "feat: WIP added functionality to aknowledge the new permission added" This reverts commit 0922fe7c5b625605dae794a1271c796ff9e36ae7. --- src/components/Dashboard/Dashboard.jsx | 39 +++----------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index b2d7810e24..7d053a5394 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -15,21 +15,15 @@ import { DEV_ADMIN_ACCOUNT_CUSTOM_WARNING_MESSAGE_DEV_ENV_ONLY, PROTECTED_ACCOUNT_MODIFICATION_WARNING_MESSAGE, } from 'utils/constants'; -import { ENDPOINTS } from 'utils/URL'; -import axios from 'axios'; -import { getUserProfile, updateUserProfile } from 'actions/userProfile'; export function Dashboard(props) { const [popup, setPopup] = useState(false); const [filteredUserTeamIds, setFilteredUserTeamIds] = useState([]); const [summaryBarData, setSummaryBarData] = useState(null); - const { match, authUser, displayUserProfile } = props; - const { permissions, _id: userId } = displayUserProfile || {}; + const {match, authUser} = props; const checkSessionStorage = () => JSON.parse(sessionStorage.getItem('viewingUser')) ?? false; const [viewingUser, setViewingUser] = useState(checkSessionStorage); - const [displayUserId, setDisplayUserId] = useState( - match.params.userId || viewingUser?.userId || authUser.userid, - ); + const [displayUserId, setDisplayUserId] = useState(match.params.userId || viewingUser?.userId || authUser.userid); const isNotAllowedToEdit = cantUpdateDevAdminDetails(viewingUser?.email, authUser.email); const darkMode = useSelector(state => state.theme.darkMode); @@ -67,20 +61,6 @@ export function Dashboard(props) { }; }, []); - const updateAcknow = async () => { - try { - const res = await axios.put(ENDPOINTS.USER_PROFILE(userId), { - _id: userId, - isAcknowledged: true, - }); - // console.log('response', res); - if (res.status == 200) { - props.getUserProfile(userId); - } - } catch (e) { - console.log('update ack', e); - } - }; return ( - {!permissions?.isAcknowledged ? ( - - ) : null} + @@ -160,11 +136,4 @@ const mapStateToProps = state => ({ displayUserProfile: state.userProfile, }); -const mapDispatchToProps = dispatch => { - return { - updateUserProfile: data => updateUserProfile(data)(dispatch), - getUserProfile: userId => getUserProfile(userId)(dispatch), - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); +export default connect(mapStateToProps)(Dashboard); From 308009eced1cc4ea756d63fcaaeb9aad08368485 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Tue, 18 Mar 2025 23:26:51 -0400 Subject: [PATCH 10/49] feat: show modal when there is update in permission --- src/components/Header/Header.jsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 0c0fa69f5a..c5d6c6a7dc 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -60,6 +60,7 @@ import { } from '../../actions/notificationAction'; import NotificationCard from '../Notification/notificationCard'; import DarkModeButton from './DarkModeButton'; +import { getUserProfile } from '../../actions/userProfile'; export function Header(props) { const location = useLocation(); @@ -218,11 +219,16 @@ export function Header(props) { const handlePermissionChangeAck = async() => { // handle setting the ack true try { + const {firstName: name, lastName, personalLinks, adminLinks} = props.userProfile const res = await axios.put(ENDPOINTS.USER_PROFILE(userId), { - _id: userId, + // req fields for updation + firstName: name, + lastName, + personalLinks, + adminLinks, + isAcknowledged: true, }); - // console.log('response', res); if (res.status === 200) { props.getUserProfile(userId); } @@ -582,10 +588,10 @@ export function Header(props) { onClickClose={() => setPopup(prevPopup => !prevPopup)} /> )} - {props.auth.isAuthenticated && !props.userProfile?.permissions?.isAcknowledged && ( + {props.auth.isAuthenticated && props.userProfile?.permissions?.isAcknowledged===false && ( handlePermissionChangeAck} + onClickClose={handlePermissionChangeAck} /> )}
@@ -637,4 +643,5 @@ export default connect(mapStateToProps, { getAllRoles, hasPermission, getWeeklySummaries, + getUserProfile })(Header); From 049d3828b5ef349fd5109cd6434252ac9134f4a6 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Wed, 19 Mar 2025 22:51:31 -0400 Subject: [PATCH 11/49] test: update testcase for popupbar --- src/components/PopUpBar/__tests__/PopUpBar.test.jsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/PopUpBar/__tests__/PopUpBar.test.jsx b/src/components/PopUpBar/__tests__/PopUpBar.test.jsx index d34104ab75..8017cb9685 100644 --- a/src/components/PopUpBar/__tests__/PopUpBar.test.jsx +++ b/src/components/PopUpBar/__tests__/PopUpBar.test.jsx @@ -1,14 +1,9 @@ import { render, screen, fireEvent } from '@testing-library/react'; import PopUpBar from '../PopUpBar'; -const viewingUser = { - firstName: 'TestUser', - lastName: 'LastName', -}; - // render Component const renderComponent = (props = {}) => { - render(); + render(); }; // Test Cases @@ -21,7 +16,7 @@ describe('Test Suite for PopUpBar', () => { it('Test Case 2: Renders with correct text', () => { renderComponent(); - const expectedText = `You are currently viewing the header for ${viewingUser.firstName} ${viewingUser.lastName}`; + const expectedText = `PopUpBar text message`; const actualText = screen.getByText(expectedText); expect(actualText).toBeInTheDocument(); }); From 1c0609652d11df33b73f07fef9f2de638417acf3 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Thu, 20 Mar 2025 19:15:24 -0400 Subject: [PATCH 12/49] test update --- .../components/ReportHeader/__test__/ReportHeader.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js b/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js index a4eea9066b..5aed36e993 100644 --- a/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js +++ b/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js @@ -16,7 +16,7 @@ describe('ReportHeader component', () => { it('renders with default avatar when avatar prop is not provided', () => { const { container } = render( - + ); const defaultAvatarElement = container.querySelector('img[src="/pfp-default.png"]'); From 3b786eda8f117b1acda25292d63ab87667a55ac3 Mon Sep 17 00:00:00 2001 From: vinayv_456 Date: Thu, 20 Mar 2025 19:20:48 -0400 Subject: [PATCH 13/49] rollback test --- .../components/ReportHeader/__test__/ReportHeader.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js b/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js index 5aed36e993..a4eea9066b 100644 --- a/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js +++ b/src/components/Reports/sharedComponents/ReportPage/components/ReportHeader/__test__/ReportHeader.test.js @@ -16,7 +16,7 @@ describe('ReportHeader component', () => { it('renders with default avatar when avatar prop is not provided', () => { const { container } = render( - + ); const defaultAvatarElement = container.querySelector('img[src="/pfp-default.png"]'); From 91361856b9a2586654aa7113c38d54acff31b78d Mon Sep 17 00:00:00 2001 From: Angad Anil Gosain Date: Tue, 1 Apr 2025 20:40:47 -0700 Subject: [PATCH 14/49] Checked why team members data is not being rendered using logging. --- src/components/Teams/TeamMembersPopup.jsx | 14 ++++++++++++++ src/components/Teams/Teams.jsx | 1 + 2 files changed, 15 insertions(+) diff --git a/src/components/Teams/TeamMembersPopup.jsx b/src/components/Teams/TeamMembersPopup.jsx index a4a5d5a0f6..be5d17ba41 100644 --- a/src/components/Teams/TeamMembersPopup.jsx +++ b/src/components/Teams/TeamMembersPopup.jsx @@ -39,6 +39,8 @@ export const TeamMembersPopup = React.memo(props => { setDeletedPopup(!deletedPopup); }; + console.log(memberList); + const handleDelete = id => { props.onDeleteClick(`${id}`); setDeletedPopup(true); @@ -60,6 +62,7 @@ export const TeamMembersPopup = React.memo(props => { const canAssignTeamToUsers = props.hasPermission('assignTeamToUsers'); const validation = props.members.teamMembers || props.members; + console.log("Validation data:", validation); const closePopup = () => { setMemberList([]); @@ -152,6 +155,7 @@ export const TeamMembersPopup = React.memo(props => { sortedList.push(...item.toSorted(sortByAlpha)); }); } + console.log("Sorted List:", sortedList); setMemberList(sortedList); }; @@ -188,6 +192,16 @@ export const TeamMembersPopup = React.memo(props => { return newMemberVisibility; }; + // useEffect(() => { + // // Log team members whenever `props.members.teamMembers` changes + // console.log('Team members:', props.members); + + // sortList(sortOrder); + // const newMemberVisibility = getMemberVisibility(); + // setMemberVisibility(newMemberVisibility); + // }, [validation, sortOrder, props.members.teamMembers]); // Dependencies to trigger when teamMembers or sortOrder changes + + useEffect(() => { sortList(sortOrder); const newMemberVisibility = getMemberVisibility(); diff --git a/src/components/Teams/Teams.jsx b/src/components/Teams/Teams.jsx index b267d9e056..3b5db0f6f1 100644 --- a/src/components/Teams/Teams.jsx +++ b/src/components/Teams/Teams.jsx @@ -234,6 +234,7 @@ class Teams extends React.PureComponent { teampopupElements = allTeams => { const { teamMembers: members, fetching } = this.props.state.teamsTeamMembers; + console.log("state in teampopupElements:", this.props.state); const selectedTeamData = allTeams ? allTeams.filter(team => team.teamName === this.state.selectedTeam) : []; From 2dcf61c24fbb95b26c62ea186605e32865622212 Mon Sep 17 00:00:00 2001 From: Angad Anil Gosain Date: Tue, 1 Apr 2025 20:48:58 -0700 Subject: [PATCH 15/49] Added console log to check if data is being passed correctly. --- src/components/Teams/Teams.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Teams/Teams.jsx b/src/components/Teams/Teams.jsx index 3b5db0f6f1..b267d9e056 100644 --- a/src/components/Teams/Teams.jsx +++ b/src/components/Teams/Teams.jsx @@ -234,7 +234,6 @@ class Teams extends React.PureComponent { teampopupElements = allTeams => { const { teamMembers: members, fetching } = this.props.state.teamsTeamMembers; - console.log("state in teampopupElements:", this.props.state); const selectedTeamData = allTeams ? allTeams.filter(team => team.teamName === this.state.selectedTeam) : []; From 9f9bd5a93fcf8d0fd757541318c24e0fccd8d217 Mon Sep 17 00:00:00 2001 From: Amalesh Arivanan Date: Tue, 1 Apr 2025 21:39:28 -0700 Subject: [PATCH 16/49] TSAForm Page 1: Initial draft --- src/components/TSAForm/pages/TSAFormPage1.js | 10 ++++++++++ src/routes.js | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/components/TSAForm/pages/TSAFormPage1.js diff --git a/src/components/TSAForm/pages/TSAFormPage1.js b/src/components/TSAForm/pages/TSAFormPage1.js new file mode 100644 index 0000000000..fd20d38e73 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage1.js @@ -0,0 +1,10 @@ +function Page1() { + return ( +
+

✅ TSA Form Loaded!

+

If you are seeing this, routing and rendering work!

+
+ ); +} + +export default Page1; diff --git a/src/routes.js b/src/routes.js index 67126feeaf..5b62412e6b 100644 --- a/src/routes.js +++ b/src/routes.js @@ -23,6 +23,7 @@ import Page3 from './components/HGNForm/pages/Page3'; import Page4 from './components/HGNForm/pages/Page4'; import Page5 from './components/HGNForm/pages/Page5'; import Page6 from './components/HGNForm/pages/Page6'; +import TSAFormPage1 from './components/TSAForm/pages/TSAFormPage1'; import Timelog from './components/Timelog'; import LessonForm from './components/BMDashboard/Lesson/LessonForm'; import UserProfileEdit from './components/UserProfile/UserProfileEdit'; @@ -436,10 +437,11 @@ export default ( - + + -); +); \ No newline at end of file From 1b5a651e6417afefc65507759d429b31eb474b1b Mon Sep 17 00:00:00 2001 From: Amalesh Arivanan Date: Wed, 2 Apr 2025 17:36:58 -0700 Subject: [PATCH 17/49] TSAForm Frontend --- src/components/TSAForm/pages/TSAFormPage1.js | 469 ++++++++- src/components/TSAForm/pages/TSAFormPage2.js | 617 ++++++++++++ src/components/TSAForm/pages/TSAFormPage3.js | 952 +++++++++++++++++++ src/components/TSAForm/pages/TSAFormPage4.js | 676 +++++++++++++ src/components/TSAForm/pages/TSAFormPage5.js | 481 ++++++++++ src/components/TSAForm/pages/TSAFormPage6.js | 329 +++++++ src/components/TSAForm/pages/TSAFormPage7.js | 390 ++++++++ src/components/TSAForm/pages/TSAFormPage8.js | 86 ++ src/routes.js | 16 +- 9 files changed, 4010 insertions(+), 6 deletions(-) create mode 100644 src/components/TSAForm/pages/TSAFormPage2.js create mode 100644 src/components/TSAForm/pages/TSAFormPage3.js create mode 100644 src/components/TSAForm/pages/TSAFormPage4.js create mode 100644 src/components/TSAForm/pages/TSAFormPage5.js create mode 100644 src/components/TSAForm/pages/TSAFormPage6.js create mode 100644 src/components/TSAForm/pages/TSAFormPage7.js create mode 100644 src/components/TSAForm/pages/TSAFormPage8.js diff --git a/src/components/TSAForm/pages/TSAFormPage1.js b/src/components/TSAForm/pages/TSAFormPage1.js index fd20d38e73..4c89cd9337 100644 --- a/src/components/TSAForm/pages/TSAFormPage1.js +++ b/src/components/TSAForm/pages/TSAFormPage1.js @@ -1,10 +1,469 @@ -function Page1() { +import { useHistory } from 'react-router-dom'; + +function TSAFormPage1() { + const history = useHistory(); + const handleNextClick = () => { + const requiredFields = ['email', 'fullname', 'professionaltitle']; + const radios = document.querySelector('input[name="professionalExperience"]:checked'); + const checkboxes = document.querySelectorAll('input[name="areaofExpertise"]:checked'); + + let isValid = true; + + requiredFields.forEach(field => { + const input = document.querySelector(`input[name="${field}"]`); + if (!input || !input.value.trim()) { + isValid = false; + } + }); + + if (!radios || checkboxes.length === 0) { + isValid = false; + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage2'); + }; return ( -
-

✅ TSA Form Loaded!

-

If you are seeing this, routing and rendering work!

+
+ {/* Banner Box */} +
+
+
+ + {/* Introduction Content Box */} +
+ {/* Title Bar inside content box */} +
+ Technical Support and Advisory Volunteer Agreement +
+ + {/* Content */} +
+

+ This questionnaire is for those interested in helping support One Community as a member + of the all-volunteer Sustainable Infrastructure Technical Support and Advisory Team. It + includes an assessment of your strengths, interests, and availability, followed by our + standard volunteer agreement. +

+

It contains these 6 parts:

+
    +
  • General Questions
  • +
  • Interests and Involvement
  • +
  • Your Participation Preferences
  • +
  • Your Design Preferences
  • +
  • Scope and Rights of Termination
  • +
  • Open Source Agreements
  • +
  • Dispute Resolution and Agreement of Terms
  • +
+

+ We are only interested in working with people who are serious about helping and making a + difference, so please take your time to complete this accurately. All answers are + required and it could take as much as an hour. +

+

+ Your answers here will help our interns and volunteers identify if you'd be a good + person to ask for input on their specific projects and/or designs. +

+

+ * Indicates required question +

+
+
+ {/* Title + Intro */} +
+
+ General Questions +
+
+

These are the basics we need to understand your experience and areas of expertise.

+
+
+ + {/* Email */} +
+ + +
+ + {/* Full Name */} +
+ + +
+ + {/* Professional Tile */} +
+ + +
+ + {/* Years of Professional Experience */} +
+ + + {['1-5', '5-7', '7-9', '10-14', '15-24', '25+'].map((option, index) => ( + + ))} +
+ + {/* Areas of Expertise */} +
+
+ + Areas of Expertise: (Check all that apply) + + + * +
+ + {[ + '3D CAD modeling, drawings and assembly design', + 'Architecture', + 'Civil Engineering', + 'Construction', + 'Electrical Engineering', + 'Design and Planning Infrastructure Projects', + 'Fabrication Methods and Estimating', + 'HVAC', + 'Licensed Electrician', + 'Master Electrician', + 'Licensed Plumber', + 'Plumbing Design', + 'Master Plumber', + 'Master Carpenter', + 'Mechanical Analysis', + 'Mechanical Design', + 'Solar/Renewable/Clean Energy', + 'Structural and Design Calculations', + 'Structural Analysis', + 'Structural Design', + 'Other:', + ].map((option, index) => ( +
+ + {option === 'Other:' && ( + + )} +
+ ))} +
+ + {/* Next Button */} +
+ +
); } -export default Page1; +export default TSAFormPage1; diff --git a/src/components/TSAForm/pages/TSAFormPage2.js b/src/components/TSAForm/pages/TSAFormPage2.js new file mode 100644 index 0000000000..7c34a64769 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage2.js @@ -0,0 +1,617 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage2() { + const history = useHistory(); + + const handleNextClick = () => { + const requiredGroups = [ + 'interested', + 'availability', + 'BuildingInfrastructure', + 'FoodInfrastructure', + 'Energyinfrastructure', + 'Stewardshipinfrastructure', + ]; + + let isValid = true; + + for (const group of requiredGroups) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage3'); + }; + + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Interests and Involvement +
+
+

+ These questions help us understand your general availability and preferred areas to + help. +

+

+ * Indicates required question +

+
+
+ + {/* Overall Interest */} +
+ + + {['Somewhat Interested', 'Moderately Interested', 'Very Interested'].map( + (option, index) => ( + + ), + )} +
+ + {/* Availability */} +
+ + {[ + 'Limited Availability (My availability is unpredictable and/or likely to change)', + 'Somewhat Available (My availability is limited, but I am happy to help a few hours when I can)', + 'Moderately Available (I am busy but can provide a couple of hours a week for areas I am interested)', + 'Very Available (My schedule is consistent, I have more than a few hours a week to help, and this is not expected to change)', + 'Other:', + ].map((option, index) => ( +
+ +
+ {option} + {option === 'Other:' && ( + + )} +
+
+ ))} +
+ + {/* Area of Interest Section */} +
+ {/* Title Bar */} +
+ Areas of Interest +
+ + {/* Content */} +
+

+ How interested are you in the following open source development areas of our project? +

+
+
+ {/* Building Infrastructure Interest Rating */} +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ {/* Food Infrastructure Interest Rating */} +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Energy infrastructure Interest Rating */} +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ {/* Stewardship infrastructure Interest Rating */} +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Next Button */} + +
+
+ ); +} + +export default TSAFormPage2; diff --git a/src/components/TSAForm/pages/TSAFormPage3.js b/src/components/TSAForm/pages/TSAFormPage3.js new file mode 100644 index 0000000000..af0779cdbf --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage3.js @@ -0,0 +1,952 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage3() { + const history = useHistory(); + const handleNextClick = () => { + const requiredGroups = [ + 'meetingAvailability', + 'creativeProcessParticipation', + 'collabCallsParticipation', + 'designReviewInterest', + 'techConsultationInterest', + 'VirtualReviewInterest', + 'DetailedVirtualReviewInterest', + 'DesignAndCalc', + 'ConceptualDesign', + 'VerifyingAnalyses', + 'timeCommitment', + ]; + + let isValid = true; + + for (const group of requiredGroups) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage4'); + }; + + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Your Participation Preferences +
+
+

+ This section covers how interested you are in helping with the specific processes + related to your areas of interest from the previous page. If you aren't sure about an + area, just rate it a 1. +

+

+ * Indicates required question +

+
+
+ + {[ + { + name: 'creativeProcessParticipation', + question: 'Participation in the complete creative/development process?', + }, + { + name: 'collabCallsParticipation', + question: 'Participation in virtual collaborative calls and meetings?', + }, + ].map((item, index) => ( +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ ))} + + {/* Checkbox Question Section */} +
+ + + {[ + 'N/A (My interest is below a 7)', + "Can meet if needed (Send me your questions and I'll schedule a meeting if I can help)", + 'Happy to meet but not very available (Would love to help with 1-2 meetings a month)', + 'I think meetings are important and enjoy them, contact me with your questions and we can set up a schedule. (Several meetings a month, scheduled as needed)', + "I think meetings are essential, fun and I love to collaborate. Let's coordinate a regular weekly call! (Weekly scheduled meetings with set times and required attendance of all team members)", + ].map((option, index) => ( +
+ +
+ ))} + + {/* Other Option */} +
+ + +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ +
+ + +
+ Not Interested At All + Extremely Interested +
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Anything Else Box */} +
+ + +
+ + {/* Availability Time Commitment Box */} +
+ + + {[ + '1-5 hours a month', + '5-10 hours a month', + '2-3 hours a week', + '3-5 hours a week', + '5+ hours a week', + '10+ hours a week', + ].map((option, index) => ( +
+ +
+ ))} + + {/* Other Option */} +
+ + +
+
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Next Button */} + +
+
+ ); +} + +export default TSAFormPage3; diff --git a/src/components/TSAForm/pages/TSAFormPage4.js b/src/components/TSAForm/pages/TSAFormPage4.js new file mode 100644 index 0000000000..e19dccc065 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage4.js @@ -0,0 +1,676 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage4() { + const history = useHistory(); + const handleNextClick = () => { + const requiredGroups = [ + 'EstablishingRequirements', + 'ConceptualDesigns', + 'PreliminaryDesignReview', + 'DesignVerification', + 'FinalDesignReview', + 'Detaileddrawings', + ]; + + let isValid = true; + + for (const group of requiredGroups) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage5'); + }; + + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Your Design Preferences +
+
+

+ This section covers which areas of the design, construction & implementation process you + can and most want to contribute to. If you are not sure about an area, just rate it a 1. +

+

+ * Indicates required question +

+
+
+ + {/* Establishing requirements */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ {/* Conceptual Designs */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Preliminary Design Review */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Design Verification/Analysis */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Final Design Review */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Detailed drawings and/or statement of work (SOW) */} +
+ + +
+ + Can't or don't want +
to help here +
+ + Very much can and +
want to help here +
+
+ +
+ {Array.from({ length: 10 }, (_, i) => ( + + ))} +
+
+ + {/* Anything else */} +
+ + (e.target.style.borderBottom = '2px solid #4d87a1')} + onBlur={e => (e.target.style.borderBottom = '1px solid #ccc')} + /> +
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Next Button */} + +
+
+ ); +} + +export default TSAFormPage4; diff --git a/src/components/TSAForm/pages/TSAFormPage5.js b/src/components/TSAForm/pages/TSAFormPage5.js new file mode 100644 index 0000000000..198278e297 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage5.js @@ -0,0 +1,481 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage5() { + const history = useHistory(); + const handleNextClick = () => { + const requiredGroups = ['agreementone', 'agreementtwo', 'agreementthree', 'agreementfour']; + + let isValid = true; + + for (const group of requiredGroups) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage6'); + }; + + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ One Community Consultant / Volunteer Agreement +
+
+

+ On behalf of the Board of Directors of One Community, we are happy to extend this letter + confirming the terms of your engagement as a consultant/volunteer of ONE COMMUNITY for + good and valuable consideration and clarify the nature of the services you are to + provide. +
+
Please complete all of the following sections and add your digital signature at + the end before completing any work with us. +

+

+ * Indicates required question +

+
+
+ + {/* Scope */} +
+ + +
+ + {/* Agreement 1 */} +
+ + + +
+ + {/* Task */} +
+ + +
+ + {/* Agreement 2 */} +
+ + + +
+ + {/* Period of Engagement */} +
+ + +
+ + {/* Agreement 3 */} +
+ + + +
+ + {/* Termination */} +
+ + +
+ + {/* Agreement 4 */} +
+ + + +
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Next Button */} + +
+
+ ); +} + +export default TSAFormPage5; diff --git a/src/components/TSAForm/pages/TSAFormPage6.js b/src/components/TSAForm/pages/TSAFormPage6.js new file mode 100644 index 0000000000..a06afed67e --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage6.js @@ -0,0 +1,329 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage6() { + const history = useHistory(); + const handleNextClick = () => { + const requiredGroups = ['agreementfive', 'agreementsix']; + + let isValid = true; + + for (const group of requiredGroups) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage7'); + }; + + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Open Source Agreements +
+
+ + +
+
+ + {/* Agreement 5 */} +
+ + + +
+ + {/* Access to the Website */} +
+ + +
+ + {/* Agreement 6 */} +
+ + + +
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Next Button */} + +
+
+ ); +} + +export default TSAFormPage6; diff --git a/src/components/TSAForm/pages/TSAFormPage7.js b/src/components/TSAForm/pages/TSAFormPage7.js new file mode 100644 index 0000000000..941f7f7294 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage7.js @@ -0,0 +1,390 @@ +import { useHistory } from 'react-router-dom'; + +function TSAFormPage7() { + const history = useHistory(); + + const handleNextClick = () => { + const requiredRadios = ['agreementseven', 'agreementeight']; + let isValid = true; + + // Validate radios + for (const group of requiredRadios) { + const checked = document.querySelector(`input[name="${group}"]:checked`); + if (!checked) { + isValid = false; + break; + } + } + + // Validate text input + const signature = document.querySelector('input[name="sign"]'); + if (!signature || !signature.value.trim()) { + isValid = false; + } + + if (!isValid) { + alert('Please complete all required (*) fields before proceeding.'); + return; + } + + history.push('/tsaformpage8'); + }; + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Dispute Resolution & Agreement Of Terms +
+
+ + +
+
+ + {/* Agreement 7 */} +
+ + + +
+ + {/* Agreement of Terms */} +
+ + +
+ + {/* Agreement 8 */} +
+ + + +
+ + {/* Digital Signature */} +
+ + +
+ + {/* Sign your name */} +
+
+ + * +
+ + (e.target.style.borderBottom = '2px solid #4d87a1')} + onBlur={e => (e.target.style.borderBottom = '1px solid #ccc')} + /> +
+ + {/* Navigation Buttons */} +
+ {/* Back Button */} + + + {/* Submit Button */} + +
+
+ ); +} + +export default TSAFormPage7; diff --git a/src/components/TSAForm/pages/TSAFormPage8.js b/src/components/TSAForm/pages/TSAFormPage8.js new file mode 100644 index 0000000000..a541680181 --- /dev/null +++ b/src/components/TSAForm/pages/TSAFormPage8.js @@ -0,0 +1,86 @@ +function TSAFormPage8() { + return ( +
+ {/* Banner */} +
+
+
+ + {/* Title + Intro */} +
+
+ Successfully Submitted! +
+
+ +
+
+
+ ); +} + +export default TSAFormPage8; diff --git a/src/routes.js b/src/routes.js index 5b62412e6b..9d25a847e6 100644 --- a/src/routes.js +++ b/src/routes.js @@ -24,6 +24,13 @@ import Page4 from './components/HGNForm/pages/Page4'; import Page5 from './components/HGNForm/pages/Page5'; import Page6 from './components/HGNForm/pages/Page6'; import TSAFormPage1 from './components/TSAForm/pages/TSAFormPage1'; +import TSAFormPage2 from './components/TSAForm/pages/TSAFormPage2'; +import TSAFormPage3 from './components/TSAForm/pages/TSAFormPage3'; +import TSAFormPage4 from './components/TSAForm/pages/TSAFormPage4'; +import TSAFormPage5 from './components/TSAForm/pages/TSAFormPage5'; +import TSAFormPage6 from './components/TSAForm/pages/TSAFormPage6'; +import TSAFormPage7 from './components/TSAForm/pages/TSAFormPage7'; +import TSAFormPage8 from './components/TSAForm/pages/TSAFormPage8'; import Timelog from './components/Timelog'; import LessonForm from './components/BMDashboard/Lesson/LessonForm'; import UserProfileEdit from './components/UserProfile/UserProfileEdit'; @@ -438,7 +445,14 @@ export default ( - + + + + + + + + From 1c12619fa36f654957004b52d9e3a3b780cddf09 Mon Sep 17 00:00:00 2001 From: Angad Anil Gosain Date: Wed, 2 Apr 2025 19:22:48 -0700 Subject: [PATCH 18/49] Fixed members not showing in popup. --- src/components/Teams/Team.css | 11 +- src/components/Teams/Team.jsx | 7 +- src/components/Teams/TeamMembersPopup.jsx | 122 +++++++++++----------- src/components/Teams/Teams.jsx | 6 +- src/components/Teams/TeamsOverview.css | 4 +- 5 files changed, 72 insertions(+), 78 deletions(-) diff --git a/src/components/Teams/Team.css b/src/components/Teams/Team.css index f41fca9a21..e1f692ee9c 100644 --- a/src/components/Teams/Team.css +++ b/src/components/Teams/Team.css @@ -11,7 +11,8 @@ thead { } #teams__active { - width: 10px; + width: 50px; /* Increase to provide space */ + text-align: center; } .centered-cell { @@ -126,8 +127,10 @@ tr.dark-mode:hover { } .usermanagement-actions-cell { - display: table-cell; - padding-left: 10px; + height: 35px; /* Set a proper height */ + padding: 5px 10px; + font-size: 14px; + line-height: normal; } @media (max-width: 768px) { @@ -139,5 +142,5 @@ tr.dark-mode:hover { } .overflow-container table { - min-width: 600px; + min-width: 600px; } diff --git a/src/components/Teams/Team.jsx b/src/components/Teams/Team.jsx index cb1411d9cb..2b659428ee 100644 --- a/src/components/Teams/Team.jsx +++ b/src/components/Teams/Team.jsx @@ -10,7 +10,7 @@ export function Team(props) { const canPutTeam = props.hasPermission('putTeam'); return ( - +
{props.index + 1}
@@ -25,10 +25,7 @@ export function Team(props) { } }} style={{ - all: 'unset', // Reset default button styles - cursor: 'pointer', - width: '100%', - height: '100%', + boxStyle }} aria-label={`Change status for team ${props.name}`} > diff --git a/src/components/Teams/TeamMembersPopup.jsx b/src/components/Teams/TeamMembersPopup.jsx index be5d17ba41..6a4a81fc73 100644 --- a/src/components/Teams/TeamMembersPopup.jsx +++ b/src/components/Teams/TeamMembersPopup.jsx @@ -24,6 +24,7 @@ import styles from './ToggleSwitch/ToggleSwitch.module.scss'; export const TeamMembersPopup = React.memo(props => { const darkMode = useSelector(state => state.theme.darkMode); + const hasVisibilityIconPermission = hasPermission('seeVisibilityIcon'); const [isChecked, setIsChecked] = useState(1); // 0 = false, 1 = true, 2 = all const [checkedStatus, setCheckedStatus] = useState('Active'); // 0 = false, 1 = true, 2 = all const [selectedUser, setSelectedUser] = useState(undefined); @@ -333,69 +334,64 @@ export const TeamMembersPopup = React.memo(props => { - {props.fetching && ( - - - - - - )} - - {!props.fetching && memberList.length === 0 && emptyState} - - {!props.fetching && - memberList.length > 0 && - Array.isArray(props.members.teamMembers) && - props.members.teamMembers.length > 0 && - memberList.toSorted().map(user => ( - - -
-