Search Bar Filter & Displaying of "No results found" alternative solution - react-hooks

I am currently doing up a search bar, and wanted to display "No results found" if there is no match. Apart from using (searchResults.length > 0) as the condition to map out the results, I wanted to try another solution using React hooks state e.g. noResults instead, but I just keep getting an error - Uncaught TypeError: Cannot read properties of undefined (reading 'map').
//Search bar for first name
const [searchInput, setSearchInput] = useState("");
const [noResults, setNoResults] = useState(true);
const handleSearchName = ({ target }) => {
setSearchInput(target.value);
};
const searchResults =
searchInput !== ""
? nameList.filter((person) =>
person.firstName
?.toLowerCase()
.includes(searchInput.toLowerCase())
) && setNoResults(false)
: nameList;
<div className={styles["search-bar"]}>
<InputGroup>
<Button type="submit" className={styles["search-btn"]}>
<Search className={styles["search-icon"]} />
</Button>
<Form.Control
value={searchInput}
onChange={handleSearchName}
type="text"
placeholder="Search..."
className={styles["search-box"]}
/>
</InputGroup>
</div>
{noResults && searchResults.map((person, index) => (
<div key={index}>
<Card className={styles["person-card"]}>
<Card.Body>
<div className={styles["card-content"]}>
<div className={styles["person-info"]}>
<p>{person.firstName}</p>
</div>
</div>
</Card.Body>
</Card>
</div>
))}
{!noResults && <div>No results found.</div>}

Related

How can I resolve this promise from external function in React JSX?

I need some help understanding what and why this does not work when in React JSX, but does in standard JS.
First off, what is it called when you reference a var as a function?
var promiseResolve;
promiseResolve();
And second why does React return: "Uncaught TypeError: promiseResolve is not a function" when trying to call it?
I know this sounds like a intro question, but I've been doing pretty complex JS and now React web builds for five years now, and I embarrassingly don't know what it means to call an undefined function like that.
This all fits into a bigger question of trying to resolve a promise from an await in an external function via a modal, but without trying to go into detail, if the below would work in JSX, it would solve my problems.
var promiseResolve, promiseReject;
var promise = new Promise(function(resolve, reject){
promiseResolve = resolve;
promiseReject = reject;
});
promiseResolve();
For more context, I'm trying to get this to work (EDIT: request to show full code after this blurb. Everything else works, it's only recently I was asked to add a process to warn if an email was already sent):
let promiseResolve, promiseReject;
const resendAttempt = () => new Promise((resolve,reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
const resolvePromise = () => {
promiseResolve();
}
return (
<Modal... <button onclick={resolvePromise} ... /> ... />
<Form onSubmit={async (values ...
await resendAttempt();
)}
/>
)
FULL CODE, look for comments on where issue is:
import React, { useState } from 'react';
import { Formik, Form, useField, FieldArray, Field } from 'formik';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Button from 'components/Elements/Button';
import H3 from 'components/Elements/H2';
import Modal from 'react-bootstrap/Modal';
import BootstrapButton from 'react-bootstrap/Button';
import Wrapper from './Wrapper';
const TeamRecruitmentForm = props => {
const [showForm, setShowForm] = useState(true);
const [customFormError, setCustomFormError] = useState(false);
const [customFormSuccess, setCustomFormSuccess] = useState(false);
const [recruitRow, setRecruitRow] = useState({
recruitFirstName: '',
recruitLastName: '',
recruitEmail: ''
});
const captFirstName = props.userData.name ? props.userData.name.first : '';
const captLastName = props.userData.name ? props.userData.name.last : '';
const cityName = props.customGreetingFields.eventCity ? props.customGreetingFields.eventCity : '';
let messageSubject = `Join ${captFirstName} ${captLastName}\'s Leaders for Life Team`;
let promiseResolve, promiseReject;
const resendAttempt = () => new Promise((resolve,reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
// this is called with a modaal button click
const resolvePromise = () => {
promiseResolve(); // JS errror, console says it is not a function
}
const [showTeammember, setShowTeammember] = useState(false);
const [showResend, setShowResend] = useState(false);
const handleClose = () => {
console.log('handleClose');
setShowTeammember(false);
setShowResend(false);
};
const handleShow = (modal) => {
console.log('handleShow');
if (modal == 'teammember') {
setShowTeammember(true);
} else if (modal == 'resend') {
setShowResend(true);
}
};
function validateEmail(value,x) {
let error;
const filterTeamRoster = props.teamRosterActivity.filter(user => {
return user.email == value;
});
if (!value) {
error = 'Required';
} else if (!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
error = 'Invalid email address';
}
else if (filterTeamRoster.length > 0) {
handleShow('teammember');
error = 'Current Teammember';
}
return error;
}
function validateFirstName(value) {
let error;
if (!value) {
error = 'Required';
}
return error;
}
function validateLastName(value) {
let error;
if (!value) {
error = 'Required';
}
return error;
}
return (
<>
<Modal
show={showTeammember}
id={props.id}
size={props.size}
onHide={handleClose}
className={`mx-auto ${props.modalClass}`}
centered
>
<Modal.Header closeButton closeLabel="Back" className="bg-primary py-1">
<BootstrapButton
variant="link"
onClick={handleClose}
className={`text-white btn-modal-back btn-back-${props.modalClass}`}
>
<span className="fas fa-caret-left" alt="" />
Back
</BootstrapButton>
</Modal.Header>
<Modal.Body>
<H3>Current Teammember</H3>
<p>The person associated with the email address has already joined your team</p>
<Button variant="primary" className="btn-block" onClick={handleClose}>
OK
</Button>
</Modal.Body>
</Modal>
<Modal
show={showResend}
id={props.id}
size={props.size}
onHide={handleClose}
className={`mx-auto ${props.modalClass}`}
centered
>
<Modal.Header closeButton closeLabel="Back" className="bg-primary py-1">
<BootstrapButton
variant="link"
onClick={handleClose}
className={`text-white btn-modal-back btn-back-${props.modalClass}`}
>
<span className="fas fa-caret-left" alt="" />
Back
</BootstrapButton>
</Modal.Header>
<Modal.Body>
<H3>You already sent an invite to this email address.</H3>
<p>Would you like to send it again"</p>
{/* This is the button I'm using to test allowing the dupe email
form to be send */}
<Button variant="primary" className="btn-block" onClick={resolvePromise}>
OK
</Button>
</Modal.Body>
</Modal>
<Wrapper key={props.formNumber} {...props}>
{customFormError === false && customFormSuccess === true ? (
<div className="my-1">
<Row>
<Col xs={6} md={3}
className="pr-1 pr-md-2 pb-2 email-sent-container"><span className="email-sent">{recruitRow.recruitFirstName}</span></Col>
<Col xs={6} md={3}
className="pr-1 pr-md-2 pb-2 email-sent-container"><span className="email-sent">{recruitRow.recruitLastName}</span></Col>
<Col md={4}
className="pl-md-2 pb-2 email-sent-container"><span className="email-sent">{recruitRow.recruitEmail}</span></Col>
<Col xs={6} md={2}
className="pb-2">
<Button variant="primary" type="submit" disabled>
Sent!
</Button>
</Col>
</Row>
</div>
) :
(<Formik
{...props}
initialValues={{ recruits: [{firstName: "", lastName: "", emailAddress: ""}] }}
validateOnChange={false}
validateOnBlur={false}
onSubmit={ async (values, { setSubmitting, setFieldError, setStatus }) => {
// this is the array it checks in order to kick bcak option to continue
// or cancel the submissions process
const filterSentMessages = props.sentMessages.filter(user => {
return user.recipients == values['emailAddress'+props.formNumber];
});
console.log("before sleep");
if (filterSentMessages.length > 0) {
handleShow('resend');
}
// this works, but the button click in the modal
// to resolve this is the issue where I get undefined
await resendAttempt();
let recipient = `${values['firstName'+props.formNumber]} ${values['lastName'+props.formNumber]} <${encodeURIComponent(values['emailAddress'+props.formNumber])}>,`;
console.info('recipient:', recipient);
let messageBody = `<p>Dear ${values['firstName'+props.formNumber]},</p><p>... message content ...</p><p>Thank you in advance for your commitment to making an impact!</p><p>${captFirstName}!</p>`
messageBody = encodeURIComponent(messageBody);
let x = 2; // this is here to just stop sending so many test emails
if( x == 1 ) { // this is here to just stop sending so many test emails
try {
props.sendMessage(
localStorage.getItem('frId'),
messageSubject,
messageBody,
recipient,
props.eventConfig.defaultStationeryId,
);
} catch (error) {
console.log('form submit error:', error);
setShowForm(!showForm);
setSubmitting(false);
}
}
setRecruitRow({...recruitRow, recruitFirstName: values['firstName'+props.formNumber], recruitLastName: values['lastName'+props.formNumber], recruitEmail: values['emailAddress'+props.formNumber]})
setCustomFormError(false);
setCustomFormSuccess(true);
setSubmitting(false);
}}
render={({ values,errors }) => (
<Form className="my-1" id={`recruitForm${props.formNumber}`}>
<FieldArray
name="recruits"
render={(arrayHelpers) => (
<>
{(values.recruits && values.recruits.length > 0) && (
values.recruits.map((recruit, index) => (
<Row key={props.formNumber}>
<Col xs={6} md={3}
className="pr-1 pr-md-2 pb-2"
>
<label htmlFor={`firstName${props.formNumber}`} className="sr-only">
First Name
</label>
<Field
className="form-control"
type="text"
name={`firstName${props.formNumber}`}
placeholder="First Name"
id={`firstName${props.formNumber}`}
validate={validateFirstName}
/>
{errors['firstName'+props.formNumber] && <div className="text-danger" role="alert">{errors['firstName'+props.formNumber]}</div>}
</Col>
<Col xs={6} md={3}
className="pl-1 px-md-2 pb-2"
>
<label htmlFor={`lastName${props.formNumber}`} className="sr-only">
Last Name
</label>
<Field
className="form-control"
type="text"
name={`lastName${props.formNumber}`}
placeholder="Last Name"
id={`lastName${props.formNumber}`}
validate={validateLastName}
/>
{errors['lastName'+props.formNumber] && <div className="text-danger" role="alert">{errors['lastName'+props.formNumber]}</div>}
</Col>
<Col md={4}
className="pl-md-2 pb-2"
>
<label htmlFor={`emailAddress${props.formNumber}`} className="sr-only">
Email Address
</label>
<Field
className="form-control"
type="text"
name={`emailAddress${props.formNumber}`}
placeholder="Email Address"
id={`emailAddress${props.formNumber}`}
validate={validateEmail}
/>
{errors['emailAddress'+props.formNumber] && <div className="text-danger" role="alert">{errors['emailAddress'+props.formNumber]}</div>}
</Col>
<Col xs={6} md={2}
className="pb-2"
>
<Button variant="primary" type="submit">
Send
</Button>
</Col>
</Row>
))
)}
</>
)}
/>
</Form>
)}
/>
)}
</Wrapper>
</>
);
};
export default TeamRecruitmentForm;

How do I properly send an array of separated strings using react Hooks and forms?

I'm using a react form and hooks to send a post to my backend that's running Spring boot. When I send the form information through axios post it sends a formatted JSON which is perfect, but one portion of the JSON needs to be an array of strings instead it sends one long String in the array. How can I format my code to send an array of string inputs and not one large string? I know my backend works as i've tested the end point using swaggerUi and Postman, The issue is the missile array sending back a single string array element instead of multiple strings. Jackson on the backend will only parse each individually declared string
.
import React, {useEffect, useState} from "react";
import {Link, useNavigate} from "react-router-dom";
import EmpireService from "../service/EmpireService";
const CreateOrder = () => {
const [empireName, setEmpireName] = useState("");
const [hullName, setHullName] = useState("");
const [shieldType, setShieldType] = useState("");
const [weaponType, setWeaponType] = useState("");
const [missiles, setMissiles] = useState([]);
const shipOrder ={empireName,hullName,shieldType,weaponType,missiles};
const saveOrder = (e) => {
EmpireService.createOrder(shipOrder).then((response)=> {
console.log(response.data);
}).catch(error => {
console.log(error);
})
}
return (
<div>
<br></br>
<div className = "container">
<div className = "row">
<div className = "card col-md-6 offset-md-3 offset-md-3 border-success">
<div className = "card-body ">
<form>
<div className = "form-group mb-2">
<label className = "form-label">Empire Name: </label>
<input
type = "text"
placeholder='Enter Empire name'
name = "empireName"
className='form-control border-success'
value = {empireName}
onChange = {(e) => setEmpireName(e.target.value)}>
</input>
</div>
<div className = "form-group mb-2">
<label className = "form-label">Hull Name: </label>
<input type = "text"
placeholder='Enter Hullname'
name = "hullName"
className='form-control border-success'
value = {hullName}
onChange = {(e) => setHullName(e.target.value)}
>
</input>
</div>
<div className = "form-group mb-2 ">
<label className = "form-label">Shield: </label>
<input type = "text"
placeholder='Enter Shield type'
name = "shieldType"
className='form-control border-success'
value = {shieldType}
onChange = {(e) => setShieldType(e.target.value)}
>
</input>
</div>
<div className = "form-group mb-2 ">
<label className = "form-label">Weapon: </label>
<input type = "text"
placeholder='Enter desired weapon'
name = "weaponType"
className='form-control border-success'
value = {weaponType}
onChange = {(e) => setWeaponType(e.target.value)}
>
</input>
</div>
<div className = "form-group mb-2 ">
<label className = "form-label">Missiles: </label>
<input type = "text"
placeholder='Enter desired missile'
name = "missiles"
className='form-control border-success'
value = {missiles}
onChange = {(e) => setMissiles([e.target.value])}
>
</input>
</div>
<button className='btn btn-success ' onClick={(e) => saveOrder(e)} >Submit</button>
<Link to = "/dawn-parts" className='btn btn-danger'>Cancel</Link>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
export default CreateOrder;
This is the raw JSON generated after submitting the form I need the missiles array to be separate strings not a single string.
{
"empireName": "Tano",
"hullName": "hull",
"shieldType": "phase_shield",
"weaponType": "ion_cannon",
"missiles": [
"voice_of_Grace, Vengeance_of_Ended_Dreams, plasma_missile"
]
}
My axios service function to connect to the order endpoint.
createOrder(shipOrder){
return axios.post(CREATE_ORDER_URL,shipOrder);
}

GraphQL mutation on Form Click not triggering

I am trying to call Apollo Mutation Hook on form submit to create a new record in the database.
export default function NewJobForm() {
const { loading, error, data } = useQuery(GET_LOC_CAT_TYPE_QUERY);
const [newJob] = useMutation(NEW_JOB_MUTATION);
const [remote, setRemote] = useState(false);
const editorRef = useRef(null);
const log = () => {
if (editorRef.current) {
console.log(editorRef.current.getContent());
}
};
let initialFormValues = {
companyName: '',
title: '',
};
const JobSchema = yup.object({
companyName: yup.string().required('Please enter the company name.'),
title: yup.string().required('Please enter the job title.'),
});
let formValidate = (values) => {
console.log(values);
const errors = {};
return errors;
};
let handleError = (field, actions) => {
field.forEach((data) => {
let field = data.param;
switch (field) {
// case 'name':
// actions.setFieldError('name', data.msg);
// break;
default:
break;
}
});
};
let formSubmit = async (values, actions) => {
console.log(values);
newJob({ variables: values });
};
return (
<>
<Formik
validationSchema={JobSchema}
validate={(values) => formValidate(values)}
onSubmit={(values, actions) => formSubmit(values, actions)}
enableReinitialize={true}
initialValues={initialFormValues}
validateOnChange={true}
validateOnBlur={false}
>
{({ handleSubmit, setFieldValue, values }) => (
<form noValidate onSubmit={handleSubmit}>
<div className="space-y-8 divide-y divide-gray-200">
<div>
<div>
<h3 className="text-lg font-medium leading-6 text-gray-900">
Job Details
</h3>
<p className="mt-1 text-sm text-gray-500">
This information will be displayed
publicly so be careful what you share.
</p>
</div>
<div className="grid grid-cols-1 mt-6 gap-y-6 gap-x-4 sm:grid-cols-6">
<div className="sm:col-span-4">
<TextInput
label="Company Name"
id="companyName"
name="companyName"
type="text"
placeholder="eg: Google"
helpText="Please Enter the name of the company"
/>
</div>
<div className="sm:col-span-4">
<TextInput
label="Job Title"
id="title"
name="title"
type="text"
/>
</div>
</div>
</div>
</div>
</form>
)}
</Formik>
</>
);
}
On Form Submit the console.log displays the message but the mutation network call does not seem to get triggered.

Unit test case for React Component using enzyme

I am working on reactjs 5.X version. I am writing UT with enzyme. Below is my reusable component with prop arguments. Not able to find the div tags inside of the const component.Can you help me how to get the div tags using classname or using find function to get div tags.
import React from 'react';
import styles from './democheck.css';
const democheck = ({ input, cb,
required, testCheckbox, checked, label, meta: { error } }) => (
<div id="hierrdivid" className={styles.testDivColumn}>
<div className={styles.testDiv}>
<br />
<span className={styles.testLabel}>
{label}
</span>
{required && <span className={styles.error}>
*
</span>}
<input
{...input}
name={`form-field-${input.name}`}
checked={checked}
id={input.name}
className={testCheckbox ? styles.testCheckboxError :
styles.testCheckbox}
type="checkbox"
onChange={() => {
if (cb) {
cb(document.getElementById(input.name).checked);
}
}}
/>
</div>
<div className={styles.testerrorDiv}>
{testCheckbox &&
<div className={styles.testerrorLabel}>
{label} {error}
</div>}
</div>
</div>
);
democheck.propTypes = {
input: React.PropTypes.objectOf(React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
])),
cb: React.PropTypes.func,
label: React.PropTypes.string,
meta: React.PropTypes.shape({}),`enter code here`
required: React.PropTypes.bool,
checked: React.PropTypes.bool,`enter code here`
testCheckbox: React.PropTypes.bool
};

Using redux-form I'm losing focus after typing the first character

I'm using redux-form and on blur validation. After I type the first character into an input element, it loses focus and I have to click in it again to continue typing. It only does this with the first character. Subsequent characters types remains focuses. Here's my basic sign in form example:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../actions/authActions';
require('../../styles/signin.scss');
class SignIn extends Component {
handleFormSubmit({ email, password }) {
this.props.signinUser({ email, password }, this.props.location);
}
renderAlert() {
if (this.props.errorMessage) {
return (
<div className="alert alert-danger">
{this.props.errorMessage}
</div>
);
} else if (this.props.location.query.error) {
return (
<div className="alert alert-danger">
Authorization required!
</div>
);
}
}
render() {
const { message, handleSubmit, prestine, reset, submitting } = this.props;
const renderField = ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<input {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
return (
<div className="row">
<div className="col-md-4 col-md-offset-4">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))} className="form-signin">
<h2 className="form-signin-heading">
Please sign in
</h2>
{this.renderAlert()}
<Field name="email" type="text" component={renderField} label="Email Address" />
<Field name="password" type="password" component={renderField} label="Password" />
<button action="submit" className="btn btn-lg btn-primary btn-block">Sign In</button>
</form>
</div>
</div>
);
}
}
function validate(values) {
const errors = {};
if (!values.email) {
errors.email = 'Enter a username';
}
if (!values.password) {
errors.password = 'Enter a password'
}
return errors;
}
function mapStateToProps(state) {
return { errorMessage: state.auth.error }
}
SignIn = reduxForm({
form: 'signin',
validate: validate
})(SignIn);
export default connect(mapStateToProps, actions)(SignIn);
This happens because you're re-defining renderField as a new component every time you render which means it looks like a new component to React so it'll unmount the original one and re-mounts the new one.
You'll need to hoist it up:
const renderField = ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<input {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
class SignIn extends Component {
...
render() {
const { message, handleSubmit, prestine, reset, submitting } = this.props;
return (
<div className="row">
<div className="col-md-4 col-md-offset-4">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))} className="form-signin">
<h2 className="form-signin-heading">
Please sign in
</h2>
{this.renderAlert()}
<Field name="email" type="text" component={renderField} label="Email Address" />
<Field name="password" type="password" component={renderField} label="Password" />
<button action="submit" className="btn btn-lg btn-primary btn-block">Sign In</button>
</form>
</div>
</div>
);
}
}
...
As #riscarrott mentioned, put renderField outside of component class .
But I am still losing focus .. And after testing, I concluded the re-rendering is done because of using curried function (return another function, and not return element . directly) .
const const renderField = (InputComponent = 'input') => ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<InputComponent {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
Then, if your renderField is a curried function :
then , don't do 😔😔😔😔:
//.....
<Field name="email" type="text" component={renderField('input')} label="Email Address" />
<Field name="desc" component={renderField('textarea')} label="Email Address" />
But , do the following 🙂🙂🙂🙂 :
// outside component class
const InputField = renderField('input');
const TextAreaField = renderField('textarea');
// inside component class
<Field name="email" type="text" component={InputField} label="Email Address" />
<Field name="desc" component={TextAreaField} label="Email Address" />
What worked for me was refactoring arrowFunction-based Component to class-based Component as the behavior of InputForm components was weird. Every time the value of each input was changed they all rerendered even after splitting each inputType to separated components. There was nothing else left to fix but changing main component to class-based. I guess it may be caused by redux-form itself.
This can also happen if you have defined styled-components inside your render function.
You should define them outside your class.
Like this:
const Row = styled.div`
justify-content:center;
`;
const Card = styled.div`
width:18rem;
padding:1rem;
`;
class Login extends Component{
i have the same problem. i resolved mine by changing the component to Class component and i removed all the css style config from render().
I had the same problem. I solved it when I added my react redux form to the store in the createForms():
export const ConfigureStore = () => {
const store = createStore(
combineReducers({
tasks: Tasks,
task: Task,
image: Image,
admin: Admin,
pageId: PageID,
fieldValues: FieldValues,
formValues: FormValues,
...createForms({
createTask: initialTask,
editTask: initialEditTask
})
}),
applyMiddleware(thunk, logger)
);
return store;
}
I had the same problem, and none of the answers worked for me.
But thanks to Advem's answer I got an idea of what could be wrong:
My form required accordion UI, and for that I had state variable in it:
const ConveyorNotificationSettingsForm = (props) => {
const {handleSubmit, formValues, dirty, reset, submitting} = props;
const [expandedSection, setExpandedSection] = useState(null);
...
with only one expanded section, that with its index equal to expandedSection .
After I extracted the accordion to a separate functional component and moved useState there, the problem was gone.
actually, this is a problem with the function component. I used a class-based component with redux form and my problem solved. I don't know the exact reason but redux form re-renders when we enter the first word and losses focus. use class-based components whenever you want to use redux form.
class StreamCreate extends React.Component{
rendorInput(formProps){
return <input {...formProps.input} />;
}
render(){
return (
<Container maxWidth="lg">
<form action="">
<Field name="title" component={this.rendorInput}/>
<Field name="description" component={this.rendorInput} />
</form>
</Container>
)
}
}
export default reduxForm({
form: 'createStream'
})( StreamCreate);

Resources