Password show/hide using Eye/EyeSlash in React - reactjs

I am trying to implement eye/eyeslash in on my Register form in React.
This is a function that's is responsible for changing visibility type and eye icon changing.
import React, { useState } from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
export const usePasswordToggle = () => {
const [visible, setVisibility] = useState();
const Icon = <FontAwesomeIcon icon={visible ? "eye-slash" : "eye"} />;
const InputType = visible ? "text" : "password";
return [InputType, Icon];
};
I am trying to implement it in component responsible for registering.
import React, { Component, createRef } from "react";
import { usePasswordToggle } from "./usePasswordToggle";
class Register1 extends React.Component {
EmailR = createRef();
UsernameR = createRef();
PasswordR = createRef();
PasswordConfirmR = createRef();
constructor(props) {
super();
this.state = {
message: "",
password: "",
confirmPassword: "",
};
}
handleSubmit = (event) => {
// alert(this.PasswordR.current.value);
// alert(this.PasswordConfirmR.current.value);
if (this.PasswordR.current.value !== this.PasswordConfirmR.current.value) {
alert("The passwords doesn't match");
return false; // The form won't submit
} else {
alert("The passwords do match");
return true; // The form will submit
}
};
onCreateAccount = () => {
let loginInfo = {
Username: this.UsernameR.current.value,
Email: this.EmailR.current.value,
Password: this.PasswordR.current.value,
};
fetch("http://localhost:5000/api/authenticate/register", {
method: "POST",
headers: { "Content-type": "application/json" },
body: JSON.stringify(loginInfo),
})
.then((r) => r.json())
.then((res) => {
if (res) {
this.setState({
message:
"New Account is Created Successfully. Check your email to verify Account.",
});
}
});
};
render() {
return (
<div>
<h2 className="FormDescription">
{" "}
Please enter Account details for registration
</h2>
<div className="Form">
<p>
<label>
Email: <input type="text" ref={this.EmailR} />
</label>
</p>
<p>
<label>
Username: <input type="text" ref={this.UsernameR} />
</label>
</p>
<div>
<label>
Password:{" "}
<input type={usePasswordToggle.InputType} ref={this.PasswordR} />
</label>
<span className="password-toogle-icon">
{usePasswordToggle.Icon}
</span>
</div>
<p>
<label>
ReenterPassword:{" "}
<input type="password" ref={this.PasswordConfirmR} />{" "}
</label>
</p>
<button onClick={this.handleSubmit}> Create </button>
<p>{this.state.message}</p>
</div>
</div>
);
}
}
export default Register1;
My password is always visible, and eye icon is even not visible on the form (it should be inside my input field, but it is not).
Focus on this code snippet:
<div>
<label>
Password: <input type={usePasswordToggle.InputType} ref={this.PasswordR} />
</label>
<span className="password-toogle-icon">{usePasswordToggle.Icon}</span>
</div>
Any suggestion what is the problem?

Change this
const [visible, setVisibility] = useState();
to this
const [visible, setVisible] = useState(true);
as the official documentation here

First, add a default value to your useState, either true or false depending on which icon you want to render first.
Then, you should add a onClick method to your icon which will toggle the visibility state. You're setting the icon based on visible value, but you never toggle the value.
onClick={() => setVisibility(!visible)}
UPDATE
You also need to execute your Hook inside your main component (because yes, you wrote what React call a Hook), like so :
const [inputType, icon] = usePasswordToggle();
But doing so, you'll get an error from React that say you cannot use a Hook within a class component due to how they work.
Basically you need to change your Register1 component to be a functional component, and not a class anymore. Look here for a quick overview on how to : https://reactjs.org/docs/components-and-props.html

Related

Conditional Rendering not working in React

I'm trying to do achieve just a simple login form for an app but for some reason cannot get my ternary operator to work. I'm simply importing the login credentials using a json file and using a submit handler to compare the user input with the data using a ternary. On submit, nothing happens. See my code below:
import React from 'react'
import customData from '../db.json'
import DocumentPage from './DocumentPage'
class MemberPortal extends React.Component {
state = {
username: "",
password: "",
}
handleUserChange = (event) => {
this.setState({username: event.target.value});
}
handlePwChange = (event) => {
this.setState({password: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
return this.state.password == customData.password ? <DocumentPage /> : alert("incorrect login information")
}
render(){
return(
<div id ="test">
<form onSubmit = {()=>this.handleSubmit}>
<label for="username">User Name:</label>
<div className="ui input">
<input type="text" id="username" value = {this.state.username} onChange = {this.handleUserChange} placeholder = "Username"></input>
</div>
<label for="password">Password:</label>
<div className="ui input">
<input type="text" id="password" value = {this.state.password} onChange = {this.handlePwChange} placeholder="Password"></input>
</div>
<input className="ui blue button" type="submit" value="Submit" onClick = {this.handleSubmit}></input>
</form>
</div>
)
}
}
export default MemberPortal;
handleSubmit is an event handler, it's a function that will be triggered when you click the button, you are not supposed to return a JSX element or anything from it. A good practice is to avoid return anything from an event handler to avoid confusion.
Generally speaking, and if you are familiar with static type language such as Typescript, an event handler should have the return type as void.
As other people have already pointed out, if you can redirect to another URL if the login is successful, or if you want to do some conditional rendering within the same component, you can set a state indicating that the login is success.
A code example can be:
class MemberPortal extends React.Component {
state = {
username: "",
password: "",
isLoginSuccessful: false
}
handleSubmit = (event) => {
event.preventDefault();
// perform login function here
....
// Login not success, alert or do anything you like
if (this.state.password !== customData.password) {
this.setState({ isLoginSuccessful: false });
alert("incorrect login information");
return;
}
// Login success, perform redirect or set the boolean flag to true for conditional rendering
this.setState({ isLoginSuccessful: true });
}
....
}

delete data in firebase using React application

Good day, I'm new React and firebase, Today, I using React and Firebase to display, add and delete data. I have some data in the firebase and display it. Now, I want delete some of the data, but I don't know. I create a button delete that whenever the user click it the data will be removed. Please help..
import React , { Component, Fragment } from 'react';
class Form extends Component {
constructor(){
super();
this.state = {
db: [],
name: "",
city: ""
}
this.changHandle = this.changHandle.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.removeData = this.removeData.bind(this)
}
componentDidMount() {
const { firestore } = this.props
firestore.collection('cafes').orderBy('name')
.onSnapshot((db) => {
const data = db.docs.map(datas => datas.data())
this.setState({
db: data
})
})
}
changHandle(event){
const {name, value} = event.target
this.setState({[name]:value})
}
handleSubmit(e){
e.preventDefault();
this.props
.firestore
.collection('cafes')
.add({city: this.state.city, name: this.state.name})
}
removeData(id){
this.props
.firestore
.collection('cafes').doc(id).delete();
}
render(){
return (
<div>
<form onSubmit={this.handleSubmit} autoComplete = "off">
<input
type="text"
name="name"
value={this.state.name}
placeholder="Name"
onChange={this.changHandle}
/><br/>
<input
type="text"
name="city"
value={this.state.city}
placeholder="City"
onChange={this.changHandle}
/><br/>
<button type="submit">Add user</button>
</form>
<p>Name:{this.state.name} {this.state.city}</p>
{this.state.db.map(data =>
<div>
<li key={data.id}>{data.name} {data.city}</li>
<button onClick={() => this.removeData(data.id)}>Delete</button>
</div>)
}
</div>
)
}
}
export default Form
MyApplication
The problem is that you are not setting an id for your document in firestore so it is just assigning a random one. In your handle submit button you need to do something like this:
const id = new Date().getTime()
this.props
.firestore
.collection('cafes').doc(id)
.add({city: this.state.city, name: this.state.name, id: id})

Saving JS State to an unordered list

class App extends Component {
constructor() {
super()
this.state = {
firstName: ""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
firstName: event.target.value
})
}
render() {
return (
<form>
<input type="text" placeholder="First Name" onChange={this.handleChange} />
<h1>{this.state.firstName}</h1>
</form>
);
}
}
export default App;
Hello all, I am currently studying React and seem to be having a hard time grasping all of it. The code that I have here works in that it will show in browser what the user is typing in the input box. What I cannot seem to figure out or get to work, is mapping what is typed in the input to stay on the screen. I.e. when I hit enter, it refreshes and the name goes away. I am trying to now create an unordered list to keep each name displayed on the screen. Any help or links would be greatly appreciated. Thank you
Just add new function (this describe what should be after submit this form) in this case You use:
event.preventDefault() -
The Event interface's preventDefault() method tells the user agent
that if the event does not get explicitly handled, its default action
should not be taken as it normally would be
onSubmit(event){
event.preventDefault()
}
and on form:
<form onSubmit={this.onSubmit}>
To create unordered list use something like this (credit for Robin Wieruch):
import React from 'react';
const initialList = [
'Learn React',
'Learn Firebase',
'Learn GraphQL',
];
const ListWithAddItem = () => {
const [value, setValue] = React.useState('');
const [list, setList] = React.useState(initialList);
const handleChange = event => {
setValue(event.target.value);
};
const handleSubmit = event => {
if (value) {
setList(list.concat(value));
}
setValue('');
event.preventDefault();
};
return (
<div>
<ul>
{list.map(item => (
<li key={item}>{item}</li>
))}
</ul>
<form onSubmit={handleSubmit}>
<input type="text" value={value} onChange={handleChange} />
<button type="submit">Add Item</button>
</form>
</div>
);
};
export default ListWithAddItem;

jest input on change not triggered/simulated

I have a React component that looks like this. It's a simple form with an input element of type email. As usual, when the user types some text, I fire a callback for the onChange event. This is what the code looks like.
import React, { PureComponent, Fragment } from "react";
import CheckCircleOutline from "mdi-react/CheckCircleOutlineIcon";
import AccountOutlineIcon from "mdi-react/AccountOutlineIcon";
import styles from "./ForgotPassword.module.scss";
class ForgotPasswordFrom extends PureComponent {
constructor() {
super();
this.state = {
email: ""
};
}
updateEmailField = e => {
this.setState({ email: e.target.value });
};
resetPassword = async e => {
e.preventDefault();
const { email } = this.state;
this.props.onSubmit(email);
};
render() {
const { showResetMessage, email } = this.props;
return (
<Fragment>
<form className="form aim-form">
{!showResetMessage ? (
<Fragment>
<div className="form__form-group">
<div className="form__form-group-field">
<div className="form__form-group-icon">
<AccountOutlineIcon />
</div>
<input
name="email"
type="email"
onChange={this.updateEmailField}
placeholder="Enter Registered Email Address"
className="email-input"
data-testid="forgot_password_input"
/>
</div>
</div>
<button
type="button"
className="btn btn-primary account__btn account__btn--small login-btn"
onClick={this.resetPassword}
data-testid="forgot_password"
>
Submit
</button>
</Fragment>
) : (
<div className={styles.messageContainer}>
<CheckCircleOutline size={50} />
<div className={styles.emailMessage}>
<div>We have sent an email to {email}.</div>
<div>Click the link in the email to reset your password</div>
</div>
</div>
)}
</form>
</Fragment>
);
}
}
export default ForgotPasswordFrom;
I am trying to write a test for when the input field's change event is simulated. This test should basically ensure that the updateEmailField function is triggered. However, no matter what I try, I cannot get the test to pass. The error I get is that the mock function is not called. Any idea what I'm doing wrong?
it("should have called the function", () => {
const wrapper = mount(<ForgotPasswordForm />);
const instance = wrapper.instance();
instance.updateEmailField = jest.fn()
const input = wrapper.find(`[data-testid='forgot_password_input']`);
input.simulate('change', { target: { value: 'test ' } });
expect(instance.updateEmailField).toHaveBeenCalled();
})
Try this code.
it("should have called the function", () => {
jest.spyOn(ForgotPasswordForm.prototype, 'updateEmailField');
const wrapper = mount(<ForgotPasswordForm />);
afterAll(() => {
ForgotPasswordForm.prototype.updateEmailField.mockRestore();
});
const input = wrapper.find(`[data-testid='forgot_password_input']`);
input.simulate('change', { target: { value: 'test ' } });
expect(wrapper.instance().updateEmailField).toHaveBeenCalled();
})

Adding an active class to a react element to be able to change css

What I want to do is to be able to toggle an active class on my elements that are dynamically created, as to be able to change the css for the selected checkbox, giving the impression that a certain filter is selected. I have looked at so many solutions and guides to make this work for my app, but I can't seem to implement it correctly. Any help would be appreciated.
Checkboxes component
import React from 'react';
const Checkbox = (props) => {
const { label, subKey } = props;
const sub1 = `${subKey}1`;
return (
<label htmlFor={sub1} className="check_label">
{label}
<input
type="checkbox"
id={sub1}
checked={props.isChecked}
onChange={props.handleCheck}
onClick={() => console.log(label)}
value={`${label.toLowerCase()}/?search=`}
/>
</label>
);
};
export default Checkbox;
and the Search component that implements checkboxes
import React, { Component } from 'react';
import Checkbox from './Checkbox';
const APIQuery = 'https://swapi.co/api/';
const searchLabels = ['Planets', 'Starships', 'People', 'Species', 'Films', 'Vehicles'];
export default class Searchbutton extends Component {
constructor(props) {
super(props);
this.state = {
endpointValue: '',
searchValue: '',
};
}
/* Funcionality to handle form and state of form */
/* Changes state of value whenever the form is changed, in realtime. */
handleChange(event) {
this.setState({ searchValue: event.target.value });
}
/* Prevents default formsubmit */
handleSubmit(event) {
event.preventDefault();
}
/* Handles state of checkboxes and sets state as to prepend necessary filter for request */
handleCheck(event) {
this.setState({ endpointValue: event.target.value });
if (this.state.endpointValue === event.target.value) {
this.setState({ endpointValue: '' });
}
}
/* Creates the checkboxes dynamically from the list of labels. */
createBoxes() {
const checkboxArray = [];
searchLabels.map(item => checkboxArray.push(
<Checkbox
key={item}
className="madeBoxes"
subKey={item}
endpointValue={this.state.endpointValue}
handleChange={e => this.handleChange(e)}
handleCheck={e => this.handleCheck(e)}
label={item}
/>,
));
return checkboxArray;
}
render() {
return (
<div className="search_content">
<div className="search_wrapper">
<form onSubmit={this.handleSubmit} method="#">
<label htmlFor="searchBar">
<input type="text" id="searchbar" className="search_bar" value={this.state.searchValue} onChange={e => this.handleChange(e)} />
</label>
<div>
<input type="submit" className="search_button" value="May the Force be with you." onClick={() => this.props.searchWithApi(APIQuery + this.state.endpointValue + this.state.searchValue)} />
</div>
</form>
</div>
<div className="checkboxes">
{this.createBoxes(this.labels)}
</div>
<div className="sort_filters">
{' '}
{/* These are options that the user can make in order to sort and filter the results.
The idea is to make it so that changing the value auto-perform a new request */}
{/* For sorting the returned objects based on user choice */}
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid, until href added */}
Choose sort method
<ul className="sorting">
<li className="sort_optn" href="#" value="lexicographical">Alphabetically</li>
<li className="sort_optn" href="#" value="by_added_date">By added date</li>
<li className="sort_optn" href="#" value="by_added_date_rev">By added date reversed</li>
</ul>
</div>
</div>
);
}
}
You don't really have to do it with react. You can reformat your code a little bit and solve it with CSS :checked pseudo-class.
In particular, don't wrap your checkbox within a label, but instead put the label after the input. Check this fiddle for example: https://jsfiddle.net/8c7a0fx5/
You can use the styled-component package. check the example below on how to use it:
import { Component } from 'react'
import { render } from 'react-dom'
import styled from 'styled-components'
const StyledCheckbox = styled.div`
label {
background: ${props => props.active ? 'red': 'white'}
}
`
class MyAwesomeComponent extends Component {
constructor(){
super()
this.state = {
isChecked: false
}
this.handleOnChange = this.handleOnChange.bind(this)
}
handleOnChange = ()=>{
this.setState({
isChecked: !this.state.isChecked,
})
}
render(){
const { isChecked } = this.state
return(
<StyledCheckbox active={isChecked}>
<label>Names</label>
<input type="checkbox" onChange={this.handleOnChange} />
</StyledCheckbox>
)
}
}
render(<MyAwesomeComponent/>, document.getElementById('root'))
Working code on codepen.io

Resources