diff --git a/src/js/components/CampaignsHome/CampaignsHomeFilter.jsx b/src/js/components/CampaignsHome/CampaignsHomeFilter.jsx index ab9871886..37e6da94c 100644 --- a/src/js/components/CampaignsHome/CampaignsHomeFilter.jsx +++ b/src/js/components/CampaignsHome/CampaignsHomeFilter.jsx @@ -4,25 +4,15 @@ import PropTypes from 'prop-types'; import React from 'react'; import styled from 'styled-components'; import { renderLog } from '../../common/utils/logging'; -import { SearchTitleTop } from '../../common/components/Style/FilterStyles'; import StateDropDownCore from '../Filter/StateDropDownCore'; -import SearchBar from '../Search/SearchBar'; -import BaseSearchbox from '../../../js/components/Search/BaseSearchbox'; +import SearchBar2024 from '../Search/SearchBar2024'; -// React functional component example function CampaignsHomeFilter (props) { renderLog('CampaignsHomeFilter functional component'); - const { classes, isSearching, listModeFiltersAvailable, searchText, stateCode } = props; + const { classes, listModeFiltersAvailable, stateCode } = props; // console.log('CampaignsHomeFilter props.listModeFiltersAvailable:', props.listModeFiltersAvailable); return ( - {/* {(isSearching && searchText) && ( - - Searching for " - {searchText} - " - - )} */} {!!(listModeFiltersAvailable) && ( {listModeFiltersAvailable.map((oneFilter) => ( @@ -48,7 +38,7 @@ function CampaignsHomeFilter (props) { )} - secondEntry.candidate_ultimate_election_date - firstEntry.candidate_ultimate_election_date; onFilterOrListChange = () => { - // console.log('onFilterOrListChange'); // Start over with full list, and apply all active filters const { listModeFilters, searchText, stateCode } = this.props; const { candidateList } = this.state; @@ -257,6 +255,7 @@ class CandidateListRoot extends Component { filteredList = filteredList.sort(this.orderByUltimateElectionDate); let searchResults = []; let hideDisplayBecauseNoSearchResults = false; + this.callbackToParentHideIfNoResults(false); if (searchText && searchText.length > 0) { const searchTextLowercase = searchText.toLowerCase(); // console.log('searchTextLowercase:', searchTextLowercase); @@ -289,6 +288,7 @@ class CandidateListRoot extends Component { }); if (searchResults.length === 0) { hideDisplayBecauseNoSearchResults = true; + this.callbackToParentHideIfNoResults(true); } if (searchResults.length > 0) { // Only allow the first politician entry to be displayed (when there are multiple candidate entries for the same politician) @@ -351,6 +351,10 @@ class CandidateListRoot extends Component { }); } + callbackToParentHideIfNoResults = (newValue) => { + this.props.onHideIfNoResultsChange(newValue); + } + render () { renderLog('CandidateListRoot'); // Set LOG_RENDER_EVENTS to log all renders const { classes, hideIfNoResults, hideTitle, searchText, titleTextForList } = this.props; @@ -435,6 +439,7 @@ class CandidateListRoot extends Component { CandidateListRoot.propTypes = { classes: PropTypes.object, hideIfNoResults: PropTypes.bool, + onHideIfNoResultsChange: PropTypes.func, hideTitle: PropTypes.bool, incomingList: PropTypes.array, incomingListTimeStampOfChange: PropTypes.number, diff --git a/src/js/components/Search/BaseSearchbox.jsx b/src/js/components/Search/BaseSearchbox.jsx index ae163190a..2dce814fa 100644 --- a/src/js/components/Search/BaseSearchbox.jsx +++ b/src/js/components/Search/BaseSearchbox.jsx @@ -65,58 +65,58 @@ const SearchInput = styled.input` `; class BaseSearchbox extends React.Component { - constructor(props) { + constructor (props) { super(props); this.state = { searchText: '' }; } handleInputChange = (event) => { this.setState({ searchText: event.target.value }, () => { - if (this.props.onChange) { - this.props.onChange(event); - } - if (this.props.onKeyDown) { - this.props.onKeyDown(event); - } - if(this.props.onFocus) { - this.props.onFocus(event); - } + if (this.props.onChange) { + this.props.onChange(event); + } + if (this.props.onKeyDown) { + this.props.onKeyDown(event); + } + if (this.props.onFocus) { + this.props.onFocus(event); + } }); } handleClear = () => { this.setState({ searchText: '' }, () => { - if (this.props.onClear) { - this.props.onClear(); - } + if (this.props.onClear) { + this.props.onClear(); + } }); } - render() { + render () { return ( {!this.state.searchText && } - - {this.state.searchText && } + {this.state.searchText && } ); } } BaseSearchbox.propTypes = { - placeholder: PropTypes.string, - onChange: PropTypes.func, - onKeyDown: PropTypes.func, - onFocus: PropTypes.func, - onBlur: PropTypes.func, - onClear: PropTypes.func, + placeholder: PropTypes.string, + onChange: PropTypes.func, + onKeyDown: PropTypes.func, + onFocus: PropTypes.func, + onBlur: PropTypes.func, + onClear: PropTypes.func, }; -export default BaseSearchbox; \ No newline at end of file +export default BaseSearchbox; diff --git a/src/js/components/Search/SearchBar.jsx b/src/js/components/Search/SearchBar.jsx index 020900860..f2ae9dab7 100644 --- a/src/js/components/Search/SearchBar.jsx +++ b/src/js/components/Search/SearchBar.jsx @@ -1,12 +1,12 @@ +import { CancelOutlined, Search } from '@mui/icons-material'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import styled from 'styled-components'; import { blurTextFieldAndroid, focusTextFieldAndroid, isIPhoneMiniOrSmaller } from '../../common/utils/cordovaUtils'; import { renderLog } from '../../common/utils/logging'; -import BaseSearchbox from '../Search/BaseSearchbox'; - /* eslint-disable jsx-a11y/control-has-associated-label */ + export default class SearchBar extends Component { constructor (props) { super(props); @@ -21,6 +21,7 @@ export default class SearchBar extends Component { } componentDidMount () { + // console.log("SearchBar, this.props.clearSearchTextNow:", this.props.clearSearchTextNow); if (this.props.clearSearchTextNow) { if (this.props.clearFunction) { this.props.clearFunction(); @@ -78,20 +79,43 @@ export default class SearchBar extends Component { render () { renderLog('SearchBar'); // Set LOG_RENDER_EVENTS to log all renders - const { placeholder } = this.props; + const { clearButton, placeholder, searchButton } = this.props; const { searchString } = this.state; return (
- focusTextFieldAndroid('SearchBar')} - onBlur={blurTextFieldAndroid} - onClear={this.clearQuery} + onBlur={blurTextFieldAndroid} /> +
+ {(clearButton && searchString && searchString.length > 0) && ( + + )} + {(searchButton) && ( + + )} +
); } @@ -105,3 +129,7 @@ SearchBar.propTypes = { searchFunction: PropTypes.func.isRequired, searchUpdateDelayTime: PropTypes.number.isRequired, }; + +const SearchInput = styled('input')` + ${isIPhoneMiniOrSmaller() ? 'font-size: 0.8rem' : ''}; +`; \ No newline at end of file diff --git a/src/js/components/Search/SearchBar2024.jsx b/src/js/components/Search/SearchBar2024.jsx new file mode 100644 index 000000000..517efd857 --- /dev/null +++ b/src/js/components/Search/SearchBar2024.jsx @@ -0,0 +1,107 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { blurTextFieldAndroid, focusTextFieldAndroid } from '../../common/utils/cordovaUtils'; +import { renderLog } from '../../common/utils/logging'; +import BaseSearchbox from './BaseSearchbox'; + +/* eslint-disable jsx-a11y/control-has-associated-label */ +export default class SearchBar2024 extends Component { + constructor (props) { + super(props); + + this.state = { + searchString: '', + }; + + this.handleKeyPress = this.handleKeyPress.bind(this); + this.updateResults = this.updateResults.bind(this); + this.clearQuery = this.clearQuery.bind(this); + } + + componentDidMount () { + if (this.props.clearSearchTextNow) { + if (this.props.clearFunction) { + this.props.clearFunction(); + } + const { searchString } = this.state; + if (searchString) { + this.setState({ + searchString: '', + }); + } + } + } + + componentDidUpdate (prevProps) { + if (this.props.clearSearchTextNow !== prevProps.clearSearchTextNow) { + if (this.props.clearSearchTextNow) { + if (this.props.clearFunction) { + this.props.clearFunction(); + } + const { searchString } = this.state; + if (searchString) { + this.setState({ + searchString: '', + }); + } + } + } + } + + componentWillUnmount () { + if (this.timer) { + clearTimeout(this.timer); + this.timer = null; + } + } + + handleKeyPress () { + if (this.timer) clearTimeout(this.timer); + this.timer = setTimeout(() => { + this.props.searchFunction(this.state.searchString); + }, this.props.searchUpdateDelayTime); + } + + clearQuery () { + this.props.clearFunction(); + this.setState({ searchString: '' }); + } + + updateResults (event) { + const searchString = event.target.value; + this.setState({ + searchString, + }); + } + + // check limit of 50 characters + render () { + renderLog('SearchBar2024'); // Set LOG_RENDER_EVENTS to log all renders + const { placeholder } = this.props; + const { searchString } = this.state; + return ( +
+ focusTextFieldAndroid('SearchBar2024')} + onBlur={blurTextFieldAndroid} + onClear={this.clearQuery} + /> +
+ ); + } +} + +SearchBar2024.propTypes = { + clearButton: PropTypes.bool, + clearFunction: PropTypes.func.isRequired, + clearSearchTextNow: PropTypes.bool, + placeholder: PropTypes.string, + searchButton: PropTypes.bool, + searchFunction: PropTypes.func.isRequired, + searchUpdateDelayTime: PropTypes.number.isRequired, +}; diff --git a/src/js/pages/Campaigns/CampaignsHome.jsx b/src/js/pages/Campaigns/CampaignsHome.jsx index 83bf66bd8..ca09ef8e1 100644 --- a/src/js/pages/Campaigns/CampaignsHome.jsx +++ b/src/js/pages/Campaigns/CampaignsHome.jsx @@ -21,6 +21,7 @@ import RepresentativeStore from '../../stores/RepresentativeStore'; import VoterStore from '../../stores/VoterStore'; import CampaignsHomeFilter from '../../components/CampaignsHome/CampaignsHomeFilter'; import CandidateListRootPlaceholder from '../../components/CampaignsHome/CandidateListRootPlaceholder'; +import colors from '../../common/components/Style/Colors'; const CandidateListRoot = React.lazy(() => import(/* webpackChunkName: 'CandidateListRoot' */ '../../components/CandidateListRoot/CandidateListRoot')); const CampaignListRoot = React.lazy(() => import(/* webpackChunkName: 'CampaignListRoot' */ '../../common/components/Campaign/CampaignListRoot')); @@ -51,6 +52,7 @@ class CampaignsHome extends Component { candidateListTimeStampOfChange: 0, filterYear: 0, isSearching: false, + hideIfNoResults: true, listModeShown: 'showUpcomingEndorsements', listModeFiltersAvailable: [], listModeFiltersTimeStampOfChange: 0, @@ -365,6 +367,7 @@ class CampaignsHome extends Component { // listOfYearsWhenCampaignExists, listOfYearsWhenCandidateExists, listOfYearsWhenRepresentativeExists, } = this.state; + let { listModeShown } = this.state; // const listOfYears = [...new Set([...listOfYearsWhenCampaignExists, ...listOfYearsWhenCandidateExists, ...listOfYearsWhenRepresentativeExists])]; // console.log('listOfYears:', listOfYears, ', setDefaultListMode:', setDefaultListMode); @@ -588,6 +591,7 @@ class CampaignsHome extends Component { } searchFunction = (searchText) => { + // console.log('CampaignsHome searchFunction searchText:', searchText); const { listModeShown, searchText: previousSearchText, stateCode: currentStateCode } = this.state; let searchingJustStarted = false; if (previousSearchText.length === 0 && searchText.length > 0) { @@ -622,6 +626,10 @@ class CampaignsHome extends Component { } } + handleHideIfNoResultsChange = (newValue) => { + this.setState({ hideIfNoResults: newValue }); + } + render () { renderLog('CampaignsHome'); // Set LOG_RENDER_EVENTS to log all renders const { @@ -656,7 +664,8 @@ class CampaignsHome extends Component {  }> + {((this.state.hideIfNoResults)) && ( + + No Candidate Found +

+ Please ensure the accuracy of the candidate's name and try your search again +

+
+ )} + {(nextReleaseFeaturesEnabled && pigCanFly) && ( }> }> }> }> }> + + {/* */} {pigCanFly && ( }> @@ -819,5 +844,22 @@ const WhatIsHappeningSection = styled('div', { // padding: 0 0 25px 0; `)); -export default CampaignsHome; +const NoSearchResult = styled.div` + margin-top: 70px; + color: ${colors.darkGrey}; + text-align: center; + font-size: 22px; + font-weight: 600; + line-height: normal; + +p{ + margin-top: 10px; + color: ${colors.darkGrey}; + text-align: center; + font-size: 16px; + font-weight: 400; + line-height: normal; +} +`; +export default CampaignsHome; diff --git a/src/js/pages/Values/OneValue.jsx b/src/js/pages/Values/OneValue.jsx index d74813740..6085f92e7 100755 --- a/src/js/pages/Values/OneValue.jsx +++ b/src/js/pages/Values/OneValue.jsx @@ -9,7 +9,7 @@ import IssueActions from '../../actions/IssueActions'; import OrganizationActions from '../../actions/OrganizationActions'; import apiCalming from '../../common/utils/apiCalming'; import { renderLog } from '../../common/utils/logging'; -import SearchBar from '../../components/Search/SearchBar'; +import SearchBar2024 from '../../components/Search/SearchBar2024'; import { PageContentContainer } from '../../components/Style/pageLayoutStyles'; import GuideList from '../../components/VoterGuide/GuideList'; import IssueStore from '../../stores/IssueStore'; @@ -22,7 +22,6 @@ const DelayedLoad = React.lazy(() => import(/* webpackChunkName: 'DelayedLoad' * const IssueCard = React.lazy(() => import(/* webpackChunkName: 'IssueCard' */ '../../components/Values/IssueCard')); const OrganizationList = React.lazy(() => import(/* webpackChunkName: 'OrganizationList' */ '../../components/Organization/OrganizationList')); - class OneValue extends Component { constructor (props) { super(props); @@ -275,7 +274,7 @@ class OneValue extends Component { )} -

-