Skip to content

Commit 55372ec

Browse files
authored
Merge pull request #2021 from trillium/ts_2015
Create TitleBoxIFrame
2 parents 68ea9e7 + c1e7267 commit 55372ec

File tree

4 files changed

+226
-2
lines changed

4 files changed

+226
-2
lines changed

client/src/components/manageProjects/editProject.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import readableEvent from './utilities/readableEvent';
55
import ProjectForm from '../ProjectForm';
66
import { simpleInputs, additionalInputsForEdit } from '../data';
77
import TitledBox from '../parts/boxes/TitledBox';
8+
import TitledBoxIFrame from '../parts/boxes/TitledBoxIFrame';
89

910
import EditIcon from '../../svg/Icon_Edit.svg?react';
1011
import PlusIcon from '../../svg/PlusIcon.svg?react';
@@ -107,6 +108,8 @@ const EditProject = ({
107108
setFormData={setFormData}
108109
/>
109110

111+
<TitledBoxIFrame projectName={projectToEdit.name} />
112+
110113
{/* Insert Project Members (Event Editors) here */}
111114
<EditProjectMembers projectToEdit={projectToEdit} />
112115

client/src/components/parts/boxes/TitledBox.jsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
11
import React from 'react';
22
import { Box, Typography, Divider } from '@mui/material';
3+
import Accordion from '@mui/material/Accordion';
4+
import AccordionDetails from '@mui/material/AccordionDetails';
5+
import AccordionSummary from '@mui/material/AccordionSummary';
6+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
7+
8+
/**
9+
* Renders a titled box component with optional badge and children content. Can be configured as an expandable accordion.
10+
* @param {Object} props - The props object.
11+
* @param {string} props.title - The title to display in the header.
12+
* @param {React.ReactNode} props.children - The content to render inside the box or accordion details.
13+
* @param {React.ReactNode} [props.badge] - Optional badge element to display in the header.
14+
* @param {Object} [props.childrenBoxSx] - Optional sx props for the children container.
15+
* @param {boolean} [props.expandable=false] - Whether the component should be an expandable accordion.
16+
* @returns {JSX.Element} The rendered TitledBox component.
17+
*/
18+
export default function TitledBox({
19+
title,
20+
children,
21+
badge,
22+
childrenBoxSx,
23+
expandable = false,
24+
}) {
25+
if (expandable) {
26+
return (
27+
<Accordion sx={{ bgcolor: '#F5F5F5', my: 3 }}>
28+
<AccordionSummary
29+
expandIcon={<ExpandMoreIcon />}
30+
aria-controls="panel-content"
31+
id="panel-header"
32+
>
33+
<Box
34+
sx={{
35+
display: 'flex',
36+
justifyContent: 'space-between',
37+
alignItems: 'center',
38+
width: '100%',
39+
}}
40+
>
41+
<Typography sx={{ fontSize: '18px', fontWeight: '600' }}>
42+
{title}
43+
</Typography>
44+
{badge}
45+
</Box>
46+
</AccordionSummary>
47+
<Divider sx={{ borderColor: 'rgba(0,0,0,1)' }} />
48+
<AccordionDetails>
49+
<Box sx={{ py: 2, px: 4, ...childrenBoxSx }}>{children}</Box>
50+
</AccordionDetails>
51+
</Accordion>
52+
);
53+
}
354

4-
export default function TitledBox({ title, children, badge, childrenBoxSx }) {
555
return (
656
<Box sx={{ bgcolor: '#F5F5F5', my: 3 }}>
757
<Box
@@ -17,7 +67,7 @@ export default function TitledBox({ title, children, badge, childrenBoxSx }) {
1767
{title}
1868
</Typography>
1969
</Box>
20-
{badge ? badge : ' '}
70+
{badge || ' '}
2171
</Box>
2272
<Divider sx={{ borderColor: 'rgba(0,0,0,1)' }} />
2373
<Box sx={{ py: 2, px: 4, ...childrenBoxSx }}>{children}</Box>
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import React, { useState } from 'react';
2+
import TitledBox from './TitledBox';
3+
import { Box, Typography, Tooltip, Button, Link } from '@mui/material';
4+
import InfoIcon from '../../../svg/InfoIcon.svg?react';
5+
6+
/**
7+
* A specialized TitledBox component for iframe-related content, with an expandable accordion and "Add New Event" badge.
8+
* @param {Object} props - The props object.
9+
* @param {Function} props.setIsCreateNew - Function to set the create new state.
10+
* @param {string} props.projectName - The project name to pre-fill in the forms (e.g., "311Data").
11+
* @returns {JSX.Element} The rendered TitledBoxIFrame component.
12+
*/
13+
export default function TitledBoxIFrame({ setIsCreateNew, projectName }) {
14+
const [formState, setFormState] = useState('hidden');
15+
16+
const onOffBoardingLogLink =
17+
'https://github.com/hackforla/product-management/issues/391';
18+
19+
const onboardingIframeSrc = `https://docs.google.com/forms/d/e/1FAIpQLSdKbq_tO0C1nLMz4XzdmFFzt3GufTs35xy83MieQj-fUlj6vA/viewform?usp=pp_url&entry.872097547=${encodeForGoogleForms(
20+
projectName
21+
)}&embedded=true`;
22+
const offboardingIframeSrc = `https://docs.google.com/forms/d/e/1FAIpQLSftp0txQkJWIwbxFTD4-w5rrq6kI8L06sHw0dvs_CmOD-4PHg/viewform?usp=pp_url&entry.1212778706=${encodeForGoogleForms(
23+
projectName
24+
)}&embedded=true`;
25+
26+
const iframeWidth = 380;
27+
const iframeHeight = 1000;
28+
29+
return (
30+
<TitledBox
31+
title="Onboarding/Offboarding Forms"
32+
expandable={true}
33+
badge={
34+
<Tooltip
35+
title="To access this form, please log in to your project's @hackforla.org email account."
36+
slotProps={{ tooltip: { sx: { fontSize: '1.2rem' } } }}
37+
>
38+
<Box
39+
sx={{
40+
display: 'flex',
41+
justifyContent: 'center',
42+
alignItems: 'center',
43+
'&:hover': { color: 'red', cursor: 'pointer' },
44+
}}
45+
onClick={() => setIsCreateNew(true)}
46+
>
47+
<InfoIcon style={{ marginRight: '7px' }} />
48+
</Box>
49+
</Tooltip>
50+
}
51+
>
52+
<Box>
53+
<FormButtons formState={formState} setFormState={setFormState} />
54+
<FormIframes
55+
formState={formState}
56+
onboardingIframeSrc={onboardingIframeSrc}
57+
offboardingIframeSrc={offboardingIframeSrc}
58+
iframeWidth={iframeWidth}
59+
iframeHeight={iframeHeight}
60+
/>
61+
<OffboardingLink onOffBoardingLogLink={onOffBoardingLogLink} />
62+
</Box>
63+
</TitledBox>
64+
);
65+
}
66+
67+
const FormButtons = ({ formState, setFormState }) => (
68+
<Box sx={{ display: 'flex', gap: '10px', marginBottom: '10px' }}>
69+
<Button
70+
onClick={() => setFormState('onboarding')}
71+
sx={{
72+
flex: 1,
73+
padding: '5px 10px',
74+
backgroundColor: formState === 'onboarding' ? 'lightblue' : '#f0f0f0',
75+
border: '1px solid #ccc',
76+
borderRadius: '4px',
77+
cursor: 'pointer',
78+
}}
79+
>
80+
Onboarding Form
81+
</Button>
82+
<Button
83+
onClick={() => setFormState('offboarding')}
84+
sx={{
85+
flex: 1,
86+
padding: '5px 10px',
87+
backgroundColor: formState === 'offboarding' ? 'lightblue' : '#f0f0f0',
88+
border: '1px solid #ccc',
89+
borderRadius: '4px',
90+
cursor: 'pointer',
91+
}}
92+
>
93+
Offboarding Form
94+
</Button>
95+
</Box>
96+
);
97+
98+
const FormIframes = ({
99+
formState,
100+
onboardingIframeSrc,
101+
offboardingIframeSrc,
102+
iframeWidth,
103+
iframeHeight,
104+
}) => (
105+
<Box>
106+
<iframe
107+
src={onboardingIframeSrc}
108+
width={iframeWidth}
109+
height={iframeHeight}
110+
style={{
111+
border: 'none',
112+
display: formState === 'onboarding' ? 'block' : 'none',
113+
}}
114+
>
115+
Loading…
116+
</iframe>
117+
<iframe
118+
src={offboardingIframeSrc}
119+
width={iframeWidth}
120+
height={iframeHeight}
121+
style={{
122+
border: 'none',
123+
display: formState === 'offboarding' ? 'block' : 'none',
124+
}}
125+
>
126+
Loading…
127+
</iframe>
128+
</Box>
129+
);
130+
131+
const OffboardingLink = ({ onOffBoardingLogLink }) => (
132+
<Box sx={{ marginTop: '10px', marginBottom: '10px' }}>
133+
<Typography
134+
variant="h3"
135+
sx={{
136+
fontWeight: 'bold',
137+
fontSize: '1.3rem',
138+
paddingTop: '10px',
139+
paddingBottom: '10px',
140+
}}
141+
>
142+
These actions are logged in the:
143+
</Typography>
144+
<Link
145+
href={onOffBoardingLogLink}
146+
target="_blank"
147+
rel="noopener noreferrer"
148+
sx={{
149+
marginBottom: '10px',
150+
marginLeft: '10px',
151+
textDecoration: 'underline',
152+
color: 'blue',
153+
}}
154+
>
155+
On / Offboarding Log
156+
</Link>
157+
</Box>
158+
);
159+
160+
/**
161+
* Encodes a string for Google Forms URLs, converting spaces to + and encoding other special characters.
162+
* @param {string} str - The string to encode.
163+
* @returns {string} The encoded string.
164+
*/
165+
function encodeForGoogleForms(str) {
166+
return encodeURIComponent(str).replace(/%20/g, '+');
167+
}

client/src/svg/InfoIcon.svg

Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)