Skip to content

Commit 1241567

Browse files
committed
feat(search): add image search functionality
1 parent 170dfff commit 1241567

File tree

2 files changed

+115
-66
lines changed

2 files changed

+115
-66
lines changed

src/components/App.jsx

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component } from 'react';
2-
import { Searchbar } from './Searchbar';
2+
import Searchbar from './Searchbar';
33
import { ImageGallery } from './ImageGallery';
4+
import ImagePortalWelcome from './ImagePortalWelcome';
45

56
import axios from 'axios';
67

@@ -19,20 +20,38 @@ class App extends Component {
1920
};
2021
}
2122

22-
async componentDidMount() {
23-
const response = await axios.get(
24-
`/?q=cat&page=1&key=${API_KEY}&image_type=photo&orientation=horizontal&per_page=12`
25-
);
26-
this.setState({ images: response.data.hits });
23+
getImages = async searchQuery => {
24+
try {
25+
const response = await axios.get(
26+
`/?q=${searchQuery}&page=1&key=${API_KEY}&image_type=photo&orientation=horizontal&per_page=12`
27+
);
28+
this.setState({ images: response.data.hits });
29+
} catch (error) {
30+
console.error('Error searching for images:', error);
31+
} finally {
32+
// for Loader
33+
}
34+
};
35+
36+
componentDidUpdate(prevProps, prevState) {
37+
if (prevProps.searchQuery !== this.props.searchQuery) {
38+
this.getImages(this.props.searchQuery);
39+
}
2740
}
2841

2942
render() {
3043
const { images } = this.state;
3144

3245
return (
3346
<>
34-
<Searchbar />
35-
<div>{images.length > 0 ? <ImageGallery images={images} /> : null}</div>
47+
<Searchbar onSearch={this.getImages} />
48+
<div>
49+
{images.length > 0 ? (
50+
<ImageGallery images={images} />
51+
) : (
52+
<ImagePortalWelcome />
53+
)}
54+
</div>
3655
</>
3756
);
3857
}

src/components/Searchbar.jsx

Lines changed: 88 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { Component } from 'react';
22
import {
33
Button,
44
Container,
@@ -10,68 +10,98 @@ import {
1010
ToggleButton,
1111
} from 'react-bootstrap';
1212

13-
export const Searchbar = () => {
14-
const [theme, setTheme] = useState('light');
13+
class Searchbar extends Component {
14+
constructor(props) {
15+
super(props);
1516

16-
const radios = [
17-
{ name: 'Light', value: 'light' },
18-
{ name: 'Dark', value: 'dark' },
19-
];
17+
this.state = {
18+
theme: 'light',
19+
searchQuery: '',
20+
};
2021

21-
const handleThemeChange = selectedTheme => {
22-
setTheme(selectedTheme);
22+
this.radios = [
23+
{ name: 'Light', value: 'light' },
24+
{ name: 'Dark', value: 'dark' },
25+
];
26+
}
27+
28+
handleThemeChange = selectedTheme => {
29+
this.setState({ theme: selectedTheme });
2330

2431
document.documentElement.setAttribute('data-bs-theme', selectedTheme);
2532
};
2633

27-
return (
28-
<div>
29-
<Navbar bg={theme} variant={theme} fixed="top">
30-
<Container className="justify-content-center pt-1 pb-1">
31-
<Row className="mb-2 mb-md-0 justify-content-between align-items-center w-100">
32-
<Navbar.Brand as={Col} xs={2}>
33-
Image Finder
34-
</Navbar.Brand>
34+
handleInputChange = e => {
35+
this.setState({ searchQuery: e.target.value });
36+
};
37+
38+
handleSubmit = e => {
39+
e.preventDefault();
40+
41+
const { onSearch } = this.props;
42+
const { searchQuery } = this.state;
43+
44+
onSearch(searchQuery);
45+
};
46+
47+
render() {
48+
const { theme, searchQuery } = this.state;
49+
50+
return (
51+
<div>
52+
<Navbar bg={theme} variant={theme} fixed="top">
53+
<Container className="justify-content-center pt-1 pb-1">
54+
<Row className="mb-2 mb-md-0 justify-content-between align-items-center w-100">
55+
<Navbar.Brand as={Col} xs={2}>
56+
Image Finder
57+
</Navbar.Brand>
58+
59+
<ButtonGroup
60+
as={Col}
61+
xs={2}
62+
md={{ order: 'last' }}
63+
className="mb-2 mb-md-0 d-flex justify-content-end"
64+
>
65+
{this.radios.map((radio, idx) => (
66+
<ToggleButton
67+
key={idx}
68+
id={`theme-radio-${idx}`}
69+
type="radio"
70+
variant={`outline-${theme === 'light' ? 'dark' : 'light'}`}
71+
name="theme"
72+
value={radio.value}
73+
checked={theme === radio.value}
74+
onChange={() => this.handleThemeChange(radio.value)}
75+
>
76+
{radio.name}
77+
</ToggleButton>
78+
))}
79+
</ButtonGroup>
3580

36-
<ButtonGroup
37-
as={Col}
38-
xs={2}
39-
md={{ order: 'last' }}
40-
className="mb-2 mb-md-0 d-flex justify-content-end"
41-
>
42-
{radios.map((radio, idx) => (
43-
<ToggleButton
44-
key={idx}
45-
id={`theme-radio-${idx}`}
46-
type="radio"
47-
variant={`outline-${theme === 'light' ? 'dark' : 'light'}`}
48-
name="theme"
49-
value={radio.value}
50-
checked={theme === radio.value}
51-
onChange={() => handleThemeChange(radio.value)}
52-
>
53-
{radio.name}
54-
</ToggleButton>
55-
))}
56-
</ButtonGroup>
81+
<Col xs={12} md={6}>
82+
<Form onSubmit={this.handleSubmit} className="d-flex">
83+
<Form.Control
84+
type="text"
85+
autoComplete="off"
86+
autoFocus
87+
placeholder="Search images and photos"
88+
className="me-2"
89+
aria-label="Search"
90+
bg={theme}
91+
value={searchQuery}
92+
onChange={this.handleInputChange}
93+
/>
94+
<Button type="submit" variant="primary">
95+
Search
96+
</Button>
97+
</Form>
98+
</Col>
99+
</Row>
100+
</Container>
101+
</Navbar>
102+
</div>
103+
);
104+
}
105+
}
57106

58-
<Form className="d-flex" as={Col} xs={12} md={6}>
59-
<Form.Control
60-
type="text"
61-
autoComplete="off"
62-
autoFocus
63-
placeholder="Search images and photos"
64-
className="me-2"
65-
aria-label="Search"
66-
bg={theme}
67-
/>
68-
<Button type="submit" variant="primary">
69-
Search
70-
</Button>
71-
</Form>
72-
</Row>
73-
</Container>
74-
</Navbar>
75-
</div>
76-
);
77-
};
107+
export default Searchbar;

0 commit comments

Comments
 (0)