diff --git a/src/components/GordonDialogBox/index.tsx b/src/components/GordonDialogBox/index.tsx index 0f3775efa2..89775ffc4d 100644 --- a/src/components/GordonDialogBox/index.tsx +++ b/src/components/GordonDialogBox/index.tsx @@ -7,15 +7,15 @@ import { DialogProps, DialogTitle, } from '@mui/material'; -import { KeyboardEvent, PropsWithChildren } from 'react'; +import { KeyboardEvent, MouseEvent, MouseEventHandler, PropsWithChildren } from 'react'; type Props = { open: boolean; title: string; - buttonClicked: (event: {}) => void; + buttonClicked?: (event: KeyboardEvent | MouseEvent) => void; buttonName?: string; isButtonDisabled?: boolean; - cancelButtonClicked?: (event: {}) => void; + cancelButtonClicked?: MouseEventHandler; cancelButtonName?: string; severity?: AlertColor; } & Partial; @@ -33,7 +33,7 @@ const GordonDialogBox = ({ }: PropsWithChildren) => { const handleKeyPress = (event: KeyboardEvent) => { if ( - !isButtonDisabled && + buttonClicked && event.key === 'Enter' && event.currentTarget.classList.contains('MuiDialog-root') ) { diff --git a/src/components/GordonOffline/index.tsx b/src/components/GordonOffline/index.tsx index 29381ad9c0..908d1c176a 100644 --- a/src/components/GordonOffline/index.tsx +++ b/src/components/GordonOffline/index.tsx @@ -2,6 +2,11 @@ import { Button, Card, CardContent, Grid } from '@mui/material/'; import { Link } from 'react-router-dom'; import styles from './GordonOffline.module.css'; +/** + * @param {Object} props props + * @param {string} props.feature - Text representing the content the user tried to access + * @returns {JSX.Element} A card with a message that the user must connect to view content + */ type Props = { feature: string; }; diff --git a/src/components/GordonTooltip/index.tsx b/src/components/GordonTooltip/index.tsx index 5a19e4f929..c451d30dad 100644 --- a/src/components/GordonTooltip/index.tsx +++ b/src/components/GordonTooltip/index.tsx @@ -2,12 +2,12 @@ import { Tooltip, TooltipProps } from '@mui/material'; import HelpIcon from '@mui/icons-material/Help'; import styles from './GordonTooltip.module.css'; -const GordonTooltip = (props: TooltipProps) => { +const GordonTooltip = ({ children, title, ...OtherProps }: TooltipProps) => { return ( {props.children}} + title={{children}} + {...OtherProps} > diff --git a/src/components/Header/components/QuickSearch/index.tsx b/src/components/Header/components/QuickSearch/index.tsx index 9644740120..c1e99f7389 100644 --- a/src/components/Header/components/QuickSearch/index.tsx +++ b/src/components/Header/components/QuickSearch/index.tsx @@ -80,9 +80,9 @@ const performSearch = debounce( type Props = | { - disableLink: true; - customPlaceholderText: string; - onSearchSubmit: (person: SearchResult) => void; + disableLink?: true; + customPlaceholderText?: string; + onSearchSubmit?: (person: SearchResult) => void; searchFunction?: SearchFunction; } | { @@ -106,7 +106,7 @@ const GordonQuickSearch = ({ ? 'Offline' : customPlaceholderText ?? (width < BREAKPOINT_WIDTH ? 'People' : 'People Search'); - const handleInput = (_event: any, value: string) => { + const handleInput = (_event: React.SyntheticEvent, value: string) => { // remove special characters const query = value.replace(specialCharactersRegex, ''); @@ -118,7 +118,7 @@ const GordonQuickSearch = ({ } }; - const handleSubmit = (_event: any, person: SearchResult | null) => { + const handleSubmit = (_event: React.SyntheticEvent, person: SearchResult | null) => { if (!person) return; disableLink ? onSearchSubmit!(person) : navigate(`/profile/${person.UserName}`); }; diff --git a/src/components/PWAInstructions/index.jsx b/src/components/PWAInstructions/index.tsx similarity index 75% rename from src/components/PWAInstructions/index.jsx rename to src/components/PWAInstructions/index.tsx index 46f9ee9a61..ddd55eae17 100644 --- a/src/components/PWAInstructions/index.jsx +++ b/src/components/PWAInstructions/index.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import GetAppIcon from '@mui/icons-material/GetApp'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; +import BeforeInstallPromptEvent from '@mui/material'; import styles from './PWAInstructions.module.css'; import DesktopChromeInstall from './images/Desktop/Desktop-Chrome-Install-360.png'; @@ -118,12 +119,30 @@ const devices = { }, }; -const PWAInstructions = (props) => { - const [device, setDevice] = useState(null); - const [platform, setPlatform] = useState(null); +interface BeforeInstallPromptEvent extends Event { + readonly platforms: string[]; + readonly userChoice: Promise<{ + outcome: 'accepted' | 'dismissed'; + platform: string; + }>; + prompt(): Promise; +} + +type Props = { + open: boolean; + handleDisplay: () => void; + deferredPWAPrompt: BeforeInstallPromptEvent; +}; + +const PWAInstructions = ({ open, handleDisplay, deferredPWAPrompt }: Props) => { + const [device, setDevice] = useState(null); + const [platform, setPlatform] = useState(null); // Handles which device is selected - const handleDeviceChange = (event, selectedDevice) => { + const handleDeviceChange = ( + event: React.MouseEvent, + selectedDevice: string | null, + ) => { // Checks the selected device to prevent the user from deselecting a selected toggle if (selectedDevice === 'Desktop') { setDevice(selectedDevice); @@ -136,7 +155,10 @@ const PWAInstructions = (props) => { }; // Handles which platform is selected - const handlePlatformChange = (event, selectedPlatform) => { + const handlePlatformChange = ( + event: React.MouseEvent, + selectedPlatform: string | null, + ) => { // Checks the selected platform to prevent the user from deselecting a selected toggle if (selectedPlatform !== null) setPlatform(selectedPlatform); }; @@ -178,85 +200,97 @@ const PWAInstructions = (props) => { > Instructions for {preText} - {devices[device][platform].map((step, index) => { - /** - * The first step is processed differently from the rest in order to show a link to - * download Google Chrome. This is for all platforms except "Apple" since the PWA can - * only be installed through Safari with Apple - */ - if (index === 0 && platform !== 'Apple') { - return ( - - - { + /** + * The first step is processed differently from the rest in order to show a link to + * download Google Chrome. This is for all platforms except "Apple" since the PWA can + * only be installed through Safari with Apple + */ + if (index === 0 && platform !== 'Apple') { + return ( + + + + Step {index + 1}:  + + + {step[0]}  + click here. + + + + {step[3]} + + + ); + } + // Creates the JSX of the current step containing the instruction and its corresponding image + return ( + + - Step {index + 1}:  - - + Step {index + 1}:  + + + {step[0]} + + + - {step[0]}  - click here. - - - - {step[3]} + {step[2]} + - - ); - } - // Creates the JSX of the current step containing the instruction and its corresponding image - return ( - - - - Step {index + 1}:  - - - {step[0]} - - - - {step[2]} - - - ); - })} + ); + }) + } ); } @@ -264,7 +298,7 @@ const PWAInstructions = (props) => { function createContent() { // If the browser has quick PWA installation capability - if (props.deferredPWAPrompt) { + if (deferredPWAPrompt) { return ( { @@ -539,8 +563,8 @@ const Identification = ({ profile, myProf, isOnline, createSnackbar }) => { isAprilFools ? profileTitleAprilFools : userProfile.NickName - ? userProfile.NickName - : userProfile.FirstName + ? userProfile.NickName + : userProfile.FirstName }'s Profile`} /> ) : ( @@ -583,7 +607,7 @@ const Identification = ({ profile, myProf, isOnline, createSnackbar }) => { cliftonColor + ') border-box', } - : null + : undefined } >
{ ? // Main Photo: Default defaultUserImage : // Main Photo: Preferred - // If the given user doesn't have a preferred photo, then their default photo is shown - hasPreferredImage - ? preferredUserImage - : defaultUserImage + // If the given user doesn't have a preferred photo, then their default photo is shown + hasPreferredImage + ? preferredUserImage + : defaultUserImage }`} alt="Profile" /> @@ -664,7 +688,9 @@ const Identification = ({ profile, myProf, isOnline, createSnackbar }) => { xs={12} className={styles.identification_card_content_card_container_info_class} > - {userProfile.Class && {Class[userProfile.Class]}} + {checkIsStudent(userProfile) && userProfile.Class && ( + {Class[userProfile.Class]} + )} { }${hasMaidenName ? ` (${userProfile.MaidenName})` : ''}`} - {userProfile.JobTitle && userProfile.JobTitle !== '' && ( - - - {userProfile.JobTitle} - - - )} + {checkIsFacStaff(userProfile) && + userProfile.JobTitle && + userProfile.JobTitle !== '' && ( + + + {userProfile.JobTitle} + + + )} {userProfile.Email ? ( { - const toggleMembershipPrivacy = async (element) => { +type PrivacyProps = { + createSnackbar: (message: string, severity: AlertColor) => void; + element: MembershipView; +}; + +type OnlineProps = { + element: MembershipView; + children: JSX.Element | JSX.Element[]; +}; + +type MembershipProps = { + myProf: boolean; + membershipHistory: MembershipHistory; + createSnackbar: (message: string, severity: AlertColor) => void; +}; + +const PrivacyToggle = ({ element, createSnackbar }: PrivacyProps) => { + const toggleMembershipPrivacy = async (element: MembershipView) => { try { const update = await membershipService.setMembershipPrivacy( element.MembershipID, @@ -39,7 +56,7 @@ const PrivacyToggle = ({ element, createSnackbar }) => { return ( - + toggleMembershipPrivacy(element)} checked={!element.Privacy} @@ -47,16 +64,16 @@ const PrivacyToggle = ({ element, createSnackbar }) => { color="secondary" /> - + {element.Privacy ? 'Private' : 'Public'} ); }; -const OnlineOnlyLink = ({ element, children }) => { +const OnlineOnlyLink = ({ element, children }: OnlineProps) => { const isOnline = useNetworkStatus(); - const showPrivate = element.IsInvolvementPrivate || element.Privacy; + const showPrivate = element.Privacy; if (isOnline) { return ( { } }; -const MembershipInfoCard = ({ myProf, membershipHistory, createSnackbar }) => { +const MembershipInfoCard = ({ myProf, membershipHistory, createSnackbar }: MembershipProps) => { const isOnline = useNetworkStatus(); return ( <> diff --git a/src/components/Profile/components/MembershipsList/index.jsx b/src/components/Profile/components/MembershipsList/index.tsx similarity index 75% rename from src/components/Profile/components/MembershipsList/index.jsx rename to src/components/Profile/components/MembershipsList/index.tsx index 8063310916..f229ad37d4 100644 --- a/src/components/Profile/components/MembershipsList/index.jsx +++ b/src/components/Profile/components/MembershipsList/index.tsx @@ -1,11 +1,27 @@ -import { Button, Card, CardContent, CardHeader, Grid, List, Typography } from '@mui/material'; +import { + AlertColor, + Button, + Card, + CardContent, + CardHeader, + Grid, + List, + Typography, +} from '@mui/material'; import GordonLoader from 'components/Loader'; import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; -import membershipService from 'services/membership'; +import membershipService, { MembershipHistory } from 'services/membership'; import MembershipInfoCard from './components/MembershipInfoCard'; import styles from './MembershipsList.module.css'; +type Props = { + username: string; + myProf: boolean; + PersonType?: string; + createSnackbar: (message: string, severity: AlertColor) => void; +}; + /** * A List of memberships for display on the Profile and MyProfile views. * @@ -15,9 +31,9 @@ import styles from './MembershipsList.module.css'; * @param {Function} props.createSnackbar function to create a snackbar of whether an operation succeeded * @returns {JSX} A list of the user's memberships */ -const MembershipsList = ({ username, myProf, createSnackbar }) => { +const MembershipsList = ({ username, myProf, createSnackbar }: Props) => { const [loading, setLoading] = useState(true); - const [membershipHistories, setMembershipHistories] = useState([]); + const [membershipHistories, setMembershipHistories] = useState([]); useEffect(() => { async function loadMemberships() { @@ -44,14 +60,18 @@ const MembershipsList = ({ username, myProf, createSnackbar }) => { ); } else { - return membershipHistories.map((membership) => ( - - )); + return ( + <> + {membershipHistories.map((membership) => ( + + ))} + + ); } }; @@ -69,7 +89,7 @@ const MembershipsList = ({ username, myProf, createSnackbar }) => { ); const noteInfo = myProf && ( -
+
NOTE: Shaded areas are visible only to you and other members of the same club session. diff --git a/src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.jsx b/src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.tsx similarity index 84% rename from src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.jsx rename to src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.tsx index 7e9712ee0e..779cb15f1b 100644 --- a/src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.jsx +++ b/src/components/Profile/components/OfficeInfoList/UpdateMailDestinationDialog/index.tsx @@ -1,16 +1,16 @@ -import { FormControl, IconButton } from '@mui/material'; +import { AlertColor, FormControl, IconButton } from '@mui/material'; import EditIcon from '@mui/icons-material/Edit'; import GordonDialogBox from 'components/GordonDialogBox'; import GordonSnackbar from 'components/Snackbar'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, ReactNode } from 'react'; import userService from 'services/user'; import SearchField from 'views/PeopleSearch/components/SearchFieldList/components/SearchField'; -const UpdateMail = (props) => { +const UpdateMail = (props: { changeMailLocation: (mailStop: string) => void }) => { const [open, setOpen] = useState(false); const [mailStop, setMailStop] = useState(''); - const [snackbar, setSnackbar] = useState({ message: '', severity: null, open: false }); - const [mailStops, setMailStops] = useState([]); + const [snackbar, setSnackbar] = useState({ message: '', severity: '', open: false }); + const [mailStops, setMailStops] = useState([]); const handleSubmit = async () => { try { @@ -43,7 +43,6 @@ const UpdateMail = (props) => { buttonClicked={handleSubmit} cancelButtonName="CANCEL" cancelButtonClicked={() => setOpen(false)} - handleSubmit > { updateValue={(event) => setMailStop(event.target.value)} options={mailStops} select - size={200} - required="required" /> setSnackbar((s) => ({ ...s, open: false }))} /> diff --git a/src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.jsx b/src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.tsx similarity index 86% rename from src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.jsx rename to src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.tsx index 6a7b8a6e45..0c47c210ed 100644 --- a/src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.jsx +++ b/src/components/Profile/components/OfficeInfoList/UpdateOfficeHoursDialog/index.tsx @@ -1,14 +1,17 @@ -import { FormControl, IconButton, TextField } from '@mui/material'; +import { AlertColor, FormControl, IconButton, TextField } from '@mui/material'; import EditIcon from '@mui/icons-material/Edit'; import GordonDialogBox from 'components/GordonDialogBox'; import GordonSnackbar from 'components/Snackbar'; import { useState } from 'react'; import userService from 'services/user'; -const UpdateOfficeHours = (props) => { +const UpdateOfficeHours = (props: { + officeHours: string; + changeOfficeHours: (hours: string) => void; +}) => { const [open, setOpen] = useState(false); const [hours, setHours] = useState(props.officeHours); - const [snackbar, setSnackbar] = useState({ message: '', severity: null, open: false }); + const [snackbar, setSnackbar] = useState({ message: '', severity: '', open: false }); const maxCharacter = 4000; const handleSubmit = async () => { @@ -38,7 +41,6 @@ const UpdateOfficeHours = (props) => { buttonClicked={handleSubmit} cancelButtonName="CANCEL" cancelButtonClicked={() => setOpen(false)} - handleSubmit > { value={hours} onChange={(event) => setHours(event.target.value)} inputProps={{ maxLength: maxCharacter - 1 }} - required="required" + required /> setSnackbar((s) => ({ ...s, open: false }))} /> diff --git a/src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.jsx b/src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.tsx similarity index 85% rename from src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.jsx rename to src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.tsx index 438b5a9b33..edc62cbd12 100644 --- a/src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.jsx +++ b/src/components/Profile/components/OfficeInfoList/UpdateOfficeLocationDialog/index.tsx @@ -1,4 +1,4 @@ -import { Autocomplete, Box, IconButton, TextField } from '@mui/material'; +import { AlertColor, Autocomplete, Box, IconButton, TextField } from '@mui/material'; import EditIcon from '@mui/icons-material/Edit'; import GordonDialogBox from 'components/GordonDialogBox'; import GordonSnackbar from 'components/Snackbar'; @@ -6,12 +6,17 @@ import { useState, useEffect } from 'react'; import userService from 'services/user'; import peopleSearchService from 'services/peopleSearch'; +type Building = { + Code: string; + Description: string; +}; + const UpdateOffice = () => { const [open, setOpen] = useState(false); const [room, setRoom] = useState(''); - const [building, setBuilding] = useState(); - const [snackbar, setSnackbar] = useState({ message: '', severity: null, open: false }); - const [buildings, setBuildings] = useState([]); + const [building, setBuilding] = useState(''); + const [snackbar, setSnackbar] = useState({ message: '', severity: '', open: false }); + const [buildings, setBuildings] = useState([]); useEffect(() => { peopleSearchService.getBuildings().then(setBuildings); @@ -48,7 +53,6 @@ const UpdateOffice = () => { buttonClicked={handleSubmit} cancelButtonName="CANCEL" cancelButtonClicked={() => setOpen(false)} - handleSubmit > { options={buildings} renderInput={(params) => } getOptionLabel={(option) => option.Description} - onChange={(_event, value) => setBuilding(value.Code)} - required + onChange={(_event, value) => setBuilding(value!.Code)} /> { setSnackbar((s) => ({ ...s, open: false }))} /> diff --git a/src/components/Profile/components/OfficeInfoList/index.jsx b/src/components/Profile/components/OfficeInfoList/index.tsx similarity index 82% rename from src/components/Profile/components/OfficeInfoList/index.jsx rename to src/components/Profile/components/OfficeInfoList/index.tsx index 81712a6ab5..fe343f5e44 100644 --- a/src/components/Profile/components/OfficeInfoList/index.jsx +++ b/src/components/Profile/components/OfficeInfoList/index.tsx @@ -1,11 +1,28 @@ -import { useState } from 'react'; -import { Card, CardContent, CardHeader, Grid, List, Typography } from '@mui/material'; +import { useState, Fragment, useEffect, Children, ReactElement } from 'react'; +import { Card, CardContent, CardHeader, Grid, List, Typography, IconButton } from '@mui/material'; import ProfileInfoListItem from '../ProfileInfoListItem'; import styles from './OfficeInfoList.module.css'; import UpdateOffice from './UpdateOfficeLocationDialog'; import UpdateOfficeHours from './UpdateOfficeHoursDialog'; import UpdateMail from './UpdateMailDestinationDialog'; import GordonTooltip from 'components/GordonTooltip'; +import user from 'services/user'; +import EditIcon from '@mui/icons-material/Edit'; +import { SignalWifiStatusbarConnectedNoInternet4TwoTone } from '@mui/icons-material'; + +type Props = { + myProf: boolean; + profile: { + BuildingDescription: string; + OnCampusDepartment: string; + OnCampusRoom: string; + OnCampusPhone: string; + PersonType: string; + office_hours: string; + Mail_Location: string; + Mail_Description: string; + }; +}; const OfficeInfoList = ({ myProf, @@ -19,7 +36,7 @@ const OfficeInfoList = ({ Mail_Location, Mail_Description, }, -}) => { +}: Props) => { const [profOfficeHours, setProfOfficeHours] = useState(office_hours); const [profMailLocation, setProfMailLocation] = useState(Mail_Location); @@ -103,8 +120,8 @@ const OfficeInfoList = ({ {profMailLocation ? profMailLocation : 'Add your mail location here'} {Mail_Description && ( - - {Mail_Description} + + <>{Mail_Description} )} diff --git a/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationHeader/index.jsx b/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationHeader/index.tsx similarity index 100% rename from src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationHeader/index.jsx rename to src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationHeader/index.tsx diff --git a/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.jsx b/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.tsx similarity index 55% rename from src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.jsx rename to src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.tsx index 930bb361d1..f6739003d4 100644 --- a/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.jsx +++ b/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ConfirmationRow/index.tsx @@ -2,30 +2,36 @@ import { Typography, Grid } from '@mui/material/'; import styles from './ConfirmationRow.module.css'; import { Check, Remove } from '@mui/icons-material'; -const ConfirmationRow = ({ field, prevValue }) => { - const isCheckbox = typeof prevValue === 'boolean'; - const truthIcon = (value) => { +type Props = { + field: { Value: string | boolean; Label: string }; + prevValue: string | boolean; +}; + +const ConfirmationRow = ({ field, prevValue }: Props) => { + const truthIcon = (value: boolean) => { return value ? ( ) : ( ); }; - const currentValue = isCheckbox ? ( - truthIcon(field.Value) - ) : ( - - {`${field.Value}`} - - ); + const currentValue = + typeof field.Value === 'boolean' ? ( + truthIcon(field.Value) + ) : ( + + {field.Value} + + ); - const previousValue = isCheckbox ? ( - truthIcon(prevValue) - ) : ( - - {prevValue === '' || false ? 'No previous value' : `${prevValue}`} - - ); + const previousValue = + typeof prevValue === 'boolean' ? ( + truthIcon(prevValue) + ) : ( + + {prevValue === '' || false ? 'No previous value' : prevValue} + + ); return ( { +const ContentCard = (props: { title?: string; children: ReactNode }) => { return ( diff --git a/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.jsx b/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.tsx similarity index 69% rename from src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.jsx rename to src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.tsx index 0b2d4bcbe1..27368fb2ab 100644 --- a/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.jsx +++ b/src/components/Profile/components/PersonalInfoList/components/AlumniUpdateForm/components/ProfileUpdateField/index.tsx @@ -6,10 +6,35 @@ import { InputLabel, MenuItem, Select, + SelectChangeEvent, TextField, } from '@mui/material/'; +import { ChangeEvent, ReactNode } from 'react'; import styles from './ProfileUpdateField.module.css'; +type defaultProps = { + label: string; + name: string; + value: any; + helperText?: ReactNode; + menuItems?: string[]; + error?: boolean; +}; + +export type ProfileUpdateFieldProps = defaultProps & + ( + | { + type: 'text' | 'checkbox'; + menuItems?: undefined; + onChange: (event: ChangeEvent, child?: ReactNode) => void; + } + | { + type: 'select'; + menuItems: string[]; + onChange: (event: SelectChangeEvent, child?: ReactNode) => void; + } + ); + const ProfileUpdateField = ({ label, name, @@ -19,7 +44,7 @@ const ProfileUpdateField = ({ error, helperText, menuItems, -}) => { +}: ProfileUpdateFieldProps) => { let field; // eslint-disable-next-line default-case switch (type) { @@ -52,7 +77,7 @@ const ProfileUpdateField = ({ {label}