Button to view update logo - reactjs

Whenever the page loads, it should load a different logo, but when I click on the icon to view the password in the PASSWORD field, it reloads the logo.
I tried to leave asynchronously but it was not the case, maybe it's a problem with react hooks
export default function Login() {
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
const logo = (): string => {
switch (parseInt((Math.random() * (4 - 1) + 1).toString(), 10)) {
case 1:
return "/logo4.png";
case 2:
return "/logo2.png";
case 3:
return "/logo3.png";
default:
return "/logo3.png";
}
};
return (
<Image
src={logo().toString()}
width={150}
height={150}
alt="Página de login"
></Image>
<br />
<FormControl sx={{ m: 1, width: "25ch" }} variant="outlined">
<InputLabel htmlFor="outlined-adornment-password">
Senha
</InputLabel>
<OutlinedInput
id="outlined-adornment-password"
type={showPassword ? "text" : "password"}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
label="Senha"
placeholder="**********"
/>
</FormControl>
);
}
The expectation is not to load the logo function when clicking to view the password

Related

ReactJS Typescript Material UI Dialog Reusable Component

Please assist me. I was creating a Reusable Material UI Modal Dialog component so that I can call it from any component but it is not showing whenever I click the button on any component. See the code below :
*********************THE MODAL COMPONENT
--->ReusableDialog.tsx
import React, { useState, ReactNode } from 'react';
import { createStyles, Theme, withStyles, WithStyles } from '#material-ui/core/styles';
import { Button,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions } from '#mui/material';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
type Props = {
show: boolean,
title: string,
body: ReactNode,
onSubmitButtonClicked: () => void;
closeDialog: () => void;
};
export default function AppModalDialog(Props: Props) {
const [open, setOpen] = useState(Props.show)
return <>
<Dialog
open={Props.show}
onClose = {() => setOpen(false)}
aria-labelledby='dialog-title'
aria-describedby='dialog-description'
>
<DialogTitle id='dialog-title'> {Props.title} </DialogTitle>
<DialogContent>
<DialogContentText id='dialog-description' >{Props.body}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() =>Props.closeDialog}>Cancel</Button>
<Button autoFocus onClick={() => Props.onSubmitButtonClicked()}>Submit</Button>
</DialogActions>
</Dialog>
</>
}
*************************THE FORM THAT WILL DISPLAY IN THE MODAL
childFormDialog.tsx
interface paymentTypeProps{
paymenttype: string;
}
const baseURL = process.env.REACT_APP_API_BASE_URL_LOCAL;
const childFormDialog = (Props: paymentTypeProps) => {
const navigate = useNavigate();
const [submitting, setSubmitting] = useState("");
const [errormsg, setErrorMsg] = useState("");
const [fullname, setFullName] = useState<string>('');
const [email, setEmail] = useState<string>('');
const [phone, setPhone] = useState<string>('');
const [paymenttypes, setPaymenttypes] = useState(Props.paymenttype)
useLayoutEffect(()=>{
setFullName(secureLocalStorage.getItem('fullname').toString());
setEmail(secureLocalStorage.getItem('email').toString());
setPhone(secureLocalStorage.getItem('phone').toString());
//setPaymentType(Props.)
}, []);
const validationSchema = yup.object({
fullname: yup.string().required('Your full name is needed'),
email: yup.string().required('An email address is needed'),
phone: yup.string().required('Phone number is needed'),
amount: yup.string().required('Please type an amount'),
paymenttitle: yup.string().required('Please indicate title for this payment'),
paymentdescription: yup.string(),
});
const formik = useFormik({
initialValues: {
fullname: fullname,
email: email,
phone: phone,
amount: '',
paymenttitle: '',
paymentdescription: '',
},
validationSchema: validationSchema,
onSubmit: async (values) => {
handleFormSubmit();
}
})
const makePayment = () => {
}
const handleFormSubmit = () => {
var data = {
fullname: formik.values.fullname,
email: formik.values.email,
phone: formik.values.phone,
amount: formik.values.amount,
paymenttitle: formik.values.paymentdescription,
paymentdescription: formik.values.paymentdescription,
}
if(paymenttypes =='A') {
configPaymentAPI_A(data.amount, data.email, data.phone, data.fullname, data.paymenttitle, data.paymentdescription)
}
else{
configPaymentAPI_B(data.email, data.amount)
}
} //function closed
return <>
<form style={{width: '100%}'}}>
<div className="row px-3">
<Grid container direction={"column"} spacing={2}>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Payment Title"
name="paymenttitle"
placeholder="Payment Title"
variant="standard"
type="text"
value={formik.values.paymenttitle}
onChange={formik.handleChange}
error={formik.touched.paymenttitle && Boolean(formik.errors.paymenttitle)}
helperText={formik.touched.paymenttitle && formik.errors.paymenttitle}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CallToActionIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Full Name"
name="fullname"
placeholder="Your Full Name"
variant="standard"
type="text"
aria-readonly
value={formik.values.fullname}
onChange={formik.handleChange}
error={formik.touched.fullname && Boolean(formik.errors.fullname)}
helperText={formik.touched.fullname && formik.errors.fullname}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PersonOutlineIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Email Address"
name="email"
placeholder="Your Email"
variant="standard"
type="email"
aria-readonly
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<EmailIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Phone Number"
name="phone"
placeholder="Your Phone Number"
variant="standard"
type="number"
aria-readonly
value={formik.values.phone}
onChange={formik.handleChange}
error={formik.touched.phone && Boolean(formik.errors.phone)}
helperText={formik.touched.phone && formik.errors.phone}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PhoneIphoneIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Amount"
name="amount"
placeholder="Amount To Be Paid"
variant="standard"
type="number"
value={formik.values.amount}
onChange={formik.handleChange}
error={formik.touched.amount && Boolean(formik.errors.amount)}
helperText={formik.touched.amount && formik.errors.amount}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CallToActionIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Payment Description"
name="paymentdescription"
placeholder="Type some notes for this payment"
variant="standard"
type="text"
value={formik.values.paymentdescription}
onChange={formik.handleChange}
error={formik.touched.paymentdescription && Boolean(formik.errors.paymentdescription)}
helperText={formik.touched.paymentdescription && formik.errors.paymentdescription}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<EventNoteIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<Button
type="submit"
variant="contained"
startIcon={<SendIcon />}
disableRipple
>Remit Your Payment </Button>
</Grid>
</Grid>
</div>
</form>
</>
}
export default childFormDialog
********************THE PARENT FORM THAT CALL/INVOKE THE DIALOG ONCLICK OF A LINK
--->Parent.tsx
const [paymentTypState, setPaymentTypState] = useState<string>('');
const [modalDisplay, setModalDisplay] = useState<boolean>(false);
const [close, setClose] = useState<boolean>(true);
const [open, setOpen] = useState(false);
const onclickPaymentA = () => {
setOpen(true);
setPaymentTypState('A');
}
const onclickPaymentB = () => {
setOpen(true);
setPaymentTypState('B');
}
const handleDialogOnSubmit = () => {
}
return <>
<a onClick={onclickPaymentA}>
<img src="../assets/images/paymentA.png" style={{width:300, height: 150}}/>
</a>
<a onClick={onclickPaymentB}>
<img src="../assets/images/paymentB.png" style={{width:300, height: 150}}/>
</a>
<ReusableDialog
show = { open }
title = 'Top Up Your Wallet'
body = {<childFormDialog paymenttype={paymentTypState} />}
closeDialog = {() => setOpen(false) }
onSubmitButtonClicked = { handleDialogOnSubmit }
/>
</>
**********THE ROUTER OF THE APPLICATION THAT USES BROWSERROUTER
import React from "react";
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Login from './Login';
import Register from './Register';
import Dashboard from './Dashboard';
import Parent from './Parent';
<Route path="/login" element={<Login />}>
</Route>
<Route path="/register" element={<Register />}>
</Route>
<Route path="/dashboard" element={<AuthenticatedRoute element={<Dashboard />} />}>
<Route path="/parent" element={<AuthenticatedRoute element={<Parent />} />}>
I can navigate from other page to Parent.tsx and I can navigate from Parent.tsx to other pages. I don't have childFormDialog that will be displayed in the Material UI Dialog in the router because no page calls the childFormDialog through hyperlink or the menu link. The childFormDialog is called from the Parent.tsx file and it should displays in the Reusable Dialog Component on the same page.
The current behavior of the form when I click on the hyperlink is that it only shows a blank page and remain on the same URL without reloading/refreshing the page. The expected behavior is for the Material UI Dialog to display with the childFormDialog component displays in the Material UI Dialog.
I will appreciate your kind assistance
If you forgot to wrap your app in a BrowserRouter and attempt to instantiate the useNavigate hook, then your childFormDialog component would quietly fail and not render anything.

Toogle between upperCase and LowerCase Switch on a submitted form

I am making a website where customers can submit a form with their personal data, like address, phone and email. The form sends the submitted data to an "Answers page" where the company can copy the details into their internal system. The answers page is made as a form which is read only.
The data is sent through an strapi API, then fetched again to the answers page. Everything is working fine.
The problem is that I want a simple Toogle between uppercase and lowercase letters for the submitted answers on the answers page. For some reason I cant get it to work. I have tried with useState and LocalStorage. I can console that the actuall boolean changes between true/false, but the text dosent rerender to uppercase and lowercase. I am using a MUI switch to toogle between uppercase and lowercase.
//Settings Context
export const SettingsContext = createContext();
export const SettingsProvider = props => {
const [upperCase, setUpperCase] = useState(localStorage.getItem("upperCase"));
document.documentElement.setAttribute("upperCase", upperCase);
return (
<SettingsContext.Provider value={[ upperCase, setUpperCase ]}>
{ props.children }
</SettingsContext.Provider>
)
}
//AnswerPage
const [upperCase, setUpperCase] = useContext(SettingsContext);
return (
<>
{answers
.sort((b, a) => a.id - b.id)
.filter((item, idx) => idx < 1)
.map((item) => {
const { country, street, postal, city, phone, email, publishedAt } =
item.attributes;
const phoneFormated = phone ? phone.replace(/\s+/g, "") : "";
let countryFormated;
if(upperCase === true) {
countryFormated = country.toUpperCase();
} else {
countryFormated = country.toLowerCase();
}
<FormTextField
onClick={copyCountry}
InputProps={{
readOnly: true,
endAdornment: (
<InputAdornment position="end">
<IconButton
edge="end"
color="primary"
sx={{ boxShadow: "none" }}
onClick={copyCountry}
>
<ContentCopyIcon
sx={{ height: ".8em", width: ".8em" }}
/>
</IconButton>
</InputAdornment>
),
}}
variant="standard"
label="Country"
type="text"
defaultValue={country ? countryFormated : ""}
inputRef={countryRef}
/>
//switch
function AnswersSettingsModal({ open, handleClose }) {
const [upperCase, setUpperCase] = useContext(SettingsContext);
const handleChange = (event) => {
setUpperCase(event.target.checked);
localStorage.setItem("upperCase", event.target.checked);
document.documentElement.setAttribute("upperCase", event.target.checked);
};
return (
<ModalLayout open={open} handleClose={handleClose}>
<Typography id="transition-modal-title" variant="h6" component="h2">
Show big or small letters
</Typography>
<FormGroup>
<Stack direction="row" spacing={1} alignItems="center">
<FormControlLabel
sx={{ marginLeft: "0" }}
control={
<>
<Typography>Small letters</Typography>
<Switch
checked={upperCase}
onChange={handleChange}
name="upperCase"
/>
<Typography>Big letters</Typography>
</>
}
/>
</Stack>
</FormGroup>
<button className="btn-close" onClick={handleClose}>
Close
</button>
</ModalLayout>
);
}
export default AnswersSettingsModal;

Jest/Enzyme: Mock function in Functional Component

I have a functional component in React. Here is the code
import React, { useState, Fragment } from "react";
import { makeStyles } from "#material-ui/core/styles";
import "./K8sIPCalculator.css";
import { initialState, checkBoxLabel } from "./FormMetaData";
import { checkPositiveInteger } from "./FormDataValidation";
const useStyles = makeStyles((theme) => ({
// Styles
}));
const K8sIPCalculator = (props) => {
const classes = useStyles();
let intialStateCopy = JSON.parse(JSON.stringify(initialState));
const [data, setData] = useState(intialStateCopy);
const handleCheckBox = (path, value) => {
const newData = { ...data };
if (path === "nodes" || path === "pods") {
if (!checkPositiveInteger(value)) {
newData[path].value = value;
newData[path].helperText = "It should be a positive integer!";
} else {
newData[path].value = value;
newData[path].helperText = "";
}
} else newData[path] = value;
setData(newData);
};
const calculate = () => {
// Does some calculation and update data state
};
const onSubmit = () => {
if (data.nodes.helperText !== "" || data.pods.helperText !== "") {
alert("Data is not correct");
return;
}
calculate();
};
const onReset = () => {
intialStateCopy = JSON.parse(JSON.stringify(initialState));
setData(intialStateCopy);
};
return (
<Fragment>
<h2 className="name">K8s IP Calculator</h2>
<form className={classes.formRoot}>
<Accordion
defaultExpanded={true}
classes={{ expanded: classes.expanded }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
id="accordion1"
className={classes.summary}
>
<Typography className={classes.heading}>Results</Typography>
</AccordionSummary>
<AccordionDetails className="container">
<InputLabel className={classes.label}>
Total useable IPs required:
</InputLabel>
<TextField
disabled
className={classes.textDisabledInput}
id="ips-required-output"
variant="outlined"
value={data.total}
/>
<InputLabel className={classes.label} htmlFor="subnet-size-output">
Subnet Size required:
</InputLabel>
<TextField
disabled
className={classes.textDisabledInput}
id="subnet-size-output"
variant="outlined"
value={data.subnet_size}
/>
</AccordionDetails>
</Accordion>
<br />
<Accordion
defaultExpanded={true}
classes={{ expanded: classes.expanded }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
id="accordion2"
className={classes.summary}
>
<Typography className={classes.heading}>K8s Details</Typography>
</AccordionSummary>
<AccordionDetails className="container">
<InputLabel className={classes.label}>Nodes:</InputLabel>
<TextField
size="small"
type="number"
onChange={(e) => handleCheckBox("nodes", e.target.value)}
className={classes.textInput}
id="nodes-input"
variant="outlined"
value={data.nodes.value}
helperText={data.nodes.helperText}
/>
<InputLabel className={classes.label} htmlFor="pods-input">
Pods:
</InputLabel>
<TextField
size="small"
type="number"
onChange={(e) => handleCheckBox("pods", e.target.value)}
className={classes.textInput}
id="pods-input"
variant="outlined"
value={data.pods.value}
helperText={data.pods.helperText}
/>
<div id="nodes-error"></div>
</AccordionDetails>
</Accordion>
<div className="button-container">
<Button
id="reset-button"
className="button"
variant="outlined"
color="primary"
size="small"
onClick={onReset}
startIcon={<UndoIcon />}
>
Reset
</Button>
<Button
id="submit-button"
className="button"
variant="contained"
color="primary"
size="small"
startIcon={<SaveIcon />}
onClick={onSubmit}
>
Submit
</Button>
</div>
</form>
</Fragment>
);
};
export default K8sIPCalculator;
Things, I am trying to test,
When input changes, I want to check if handleCheckBox function has been called
When submit button is called, I want to check if calculate function has been called
How can I call the setData function to update data through Jest/Enzyme
I tried something like this
const spy = jest.spyOn(K8sIPCalculator, "calculate");
But I got
Cannot spy the calculate property because it is not a function; undefined given instead
PS: I am able to assert data change after submit is called. But I want to check if calculate function is called.
const submit = wrapper.find("button#submit-button");
submit.simulate("click");
expect(wrapper.find("input#ips-required-output").props().value).toEqual(35);
expect(wrapper.find("input#subnet-size-output").props().value).toEqual(
"/26"
);

React Material UI Custom Input hide/show password

I am trying to hide/show the password when a user clicks on the eye icon, but nothing changes.The default is the password is always visible, i want it to be always hidden.
[password text input][1]
My functions look like this
const [password, setPassword] = React.useState("");
const handleClickShowPassword = () => {setShowPassword({showPassword : showPassword}) };
const handleMouseDownPassword = () => {setShowPassword({showPassword : showPassword}) };
My text input code looks like this
<CustomInput
labelText="Password"
id="pass"
value={password}
type={showPassword ? 'text' : 'password'}
formControlProps={{
fullWidth: true
}}
inputProps={{
onChange: (event) => {
const value = event.target.value;
setPassword(value)
},
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
autoComplete: "off"
}}
/>
{
password === ""?
<p style={{color:"#D0021B"}}>{passworderror}</p>
:null
}
<p style={{color:"#D0021B"}}>{passwordexist}</p>
</GridItem>
[1]: https://i.stack.imgur.com/litjB.png
If you are using the useState Hook, then your handler should look like this:
const handleTogglePassword = () => setShowPassword(showPassword => !showPassword);
and the IconButton should look like this:
<IconButton
aria-label="toggle password visibility"
onClick={handleTogglePassword}
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
I think you mixed setState for class components and the useState for functional components.
Take a look here: https://reactjs.org/docs/hooks-reference.html#usestate

Any way to render Icon based on text field name using material UI?

<TextField
margin='dense'
fullWidth
value={this.props.value}
name={this.props.name}
type={this.props.type}
error={this.props.error !== ''}
helperText={this.props.error !== '' ? this.props.error : ' '}
onChange={ e => this.handleChange(e) }
label={this.props.label}
variant= {this.props.variant}
id={this.props.name}
InputProps={{
endAdornment: (
<AccountCircle />
),
}}
/>
Is there any way to display different Icons based on Text field name? I mean, If the name is Email then display EmailIcon. If profile then displays AccountCircle.
here is a simple solution so you can start it from here
let icon = null;
if (this.props.name === "Password") {
icon = <Visibility />;
} else if (this.props.name === "Account") {
icon = <AccountCircle />;
}
return (
<div className={classes.root}>
<TextField
label={this.props.name}
className={classNames(classes.margin, classes.textField)}
InputProps={{
endAdornment: icon
}}
/>
</div>
);
here I have put the name as a prop in this component and depend on that prop I change the icon. you can change this to switch if you wish.
hope you got an idea.
here is a link of a demo: https://codesandbox.io/s/moo68122lp
You can do it in an elegant way, by abstracting like this:
import { AccountCircle, UserIcon, PhoneIcon } from 'some/ui/library';
const icons = {
account: AccountCircle,
user: UserIcon,
phone: PhoneIcon,
};
const FieldIcon = ({ name }) => {
const Icon = icons[name];
return Icon ? (<Icon />) : null;
};
const YourComponent = props => (
<TextField
margin='dense'
fullWidth
value={props.value}
name={props.name}
type={props.type}
error={props.error !== ''}
helperText={props.error !== '' ? props.error : ' '}
label={props.label}
variant= {props.variant}
id={props.name}
InputProps={{
endAdornment: (
<FieldIcon name={props.name} />
),
}}
/>
);

Resources