diff --git a/src/components/App.tsx b/src/components/App.tsx
index e8c7d74..a3b543c 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,12 +1,17 @@
import React, { FC } from 'react'
import styled from '@emotion/styled'
import Header from './Header'
+import Home from './Home/Home'
+import { Provider } from 'react-redux'
+import store from '../redux/store'
const App: FC = () => {
return (
- {/* Happy coding! */}
+
+
+
)
}
diff --git a/src/components/Favourites/Favourites.tsx b/src/components/Favourites/Favourites.tsx
new file mode 100644
index 0000000..15295ff
--- /dev/null
+++ b/src/components/Favourites/Favourites.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import {icons} from '../../assets/icons/index'
+import { useSelector,useDispatch } from 'react-redux';
+import {itemRejected} from '../../redux/actions'
+import styled from '@emotion/styled';
+
+
+export default function Favorites() {
+
+ let favoriteImages = useSelector((state) => state) as string[];
+ let dispatch = useDispatch();
+
+
+ return (
+
+
+
+ Favorites
+
+ {favoriteImages.length ?
+ { favoriteImages.map((image,idx)=>{
+ return(
+
+
+ {
+ dispatch(itemRejected(image))
+ }} />
+
+ )
+ })
+ }
+
+
+ :
+
+ Please Add Items
+
+ }
+
+
+ )
+}
+
+const VStack = styled.div({
+ display:'flex',
+ alignItems:'center',
+ gap:'10px'
+});
+
+const DefaultMess = styled.div({
+ textAlign: 'center',
+ paddingBottom: '35px',
+ marginTop: '20px',
+})
+
+const FavoriteItems = styled.div({
+ paddingBottom: '20px',
+})
+
+const Grid = styled.div({
+ display: 'grid',
+ gridTemplateColumns: 'repeat(auto-fill, minmax(160px, 1fr))',
+ gap: '20px',
+ marginTop: '25px',
+ marginBottom: '30px',
+ width: '100%',
+ placeItems: 'center',
+})
+
+const ImageContainer = styled.div({
+ position:'relative',
+})
+
+const DogPhoto = styled.img({
+ width: '160px',
+ height: '160px'
+})
+
+const Icon = styled.img({
+ position: 'absolute',
+ right: '5px',
+ bottom: '10px'
+
+})
\ No newline at end of file
diff --git a/src/components/Home/Home.tsx b/src/components/Home/Home.tsx
new file mode 100644
index 0000000..267ef75
--- /dev/null
+++ b/src/components/Home/Home.tsx
@@ -0,0 +1,171 @@
+import React, { useState, useEffect } from 'react';
+import {icons} from '../../assets/icons/index';
+import { useSelector, useDispatch } from 'react-redux';
+import { itemFavourite, itemRejected } from '../../redux/actions';
+import styled from '@emotion/styled';
+import Favorites from '../Favourites/Favourites';
+
+export default function Home() {
+ const [searchItem, setSearchItem] = useState('');
+ const favoriteImages = useSelector((state) => state) as string[];
+ const dispatch = useDispatch();
+ const [dogImages, setDogImages] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState('');
+
+ useEffect(() => {
+ setLoading(true);
+ setError('');
+
+ fetch('https://dog.ceo/api/breed/hound/images')
+ .then((res) => res.json())
+ .then((res) => {
+ setLoading(false);
+ setDogImages(res.message.slice(0, 10));
+ })
+ .catch(() => {
+ setLoading(false);
+ setError('Failed to fetch initial dog images');
+ });
+ }, []);
+
+ function solve() {
+ setLoading(true);
+ setDogImages([]);
+ setError('');
+
+ fetch(`https://dog.ceo/api/breed/${searchItem}/images`)
+ .then((res) => res.json())
+ .then((res) => {
+ if (res.status === 'error') {
+ setError('No Data Found For The Given Breed Name');
+ } else {
+ setDogImages(res.message.slice(0, 10));
+ }
+ })
+ .catch(() => {
+ setError('An error occurred while fetching data.');
+ })
+ .finally(() => {
+ setLoading(false);
+ });
+ }
+
+ return (
+
+
+ setSearchItem(e.target.value.toLowerCase())}
+ />
+
+
+
+ {loading && Loading...
}
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {!error && dogImages.length > 0 && (
+
+ {dogImages.map((image, idx) => (
+
+
+ {
+ if (favoriteImages.includes(image)) {
+ dispatch(itemRejected(image));
+ } else {
+ dispatch(itemFavourite(image));
+ }
+ }}
+ />
+
+ ))}
+
+ )}
+
+
+
+
+
+ );
+}
+
+const SearchContainer = styled.div({
+ textAlign: 'center',
+ marginTop: '30px',
+ marginBottom: '40px',
+});
+
+const DefaultMess = styled.div({
+ textAlign: 'center',
+});
+
+const DogPhoto = styled.img({
+ width: '160px',
+ height: '160px'
+})
+
+const Grid = styled.div({
+ display: 'grid',
+ gridTemplateColumns: 'repeat(auto-fill, minmax(160px, 1fr))',
+ gap: '20px',
+ marginTop: '25px',
+ marginBottom: '30px',
+ width: '100%',
+ placeItems: 'center',
+})
+
+const Icon = styled.img({
+ position: 'absolute',
+ right: '5px',
+ bottom: '10px'
+
+})
+
+const ImageContainer = styled.div({
+ position:'relative',
+})
+
+const Input = styled.input({
+ // display:'block',
+ width:'80%',
+ height : '40px',
+ paddingLeft: '10px',
+ backgroundColor: '#F7F7F7',
+ borderRadius: '5px',
+ border: 'none'
+
+})
+
+const Button = styled.button({
+ width:'105px',
+ height:'40px',
+ backgroundColor: '#0794E3',
+ border: 'none',
+ borderRadius: '3px',
+ position: 'relative'
+})
+
+const SeachIcons = styled.img({
+ position: 'absolute',
+ top: '13px',
+ left: '11px',
+ height: '15px',
+})
+
+const HorizontalLine = styled.hr({
+ border: '1px solid #E5E5E5',
+ marginTop: '30px',
+ marginBottom: '30px',
+})
\ No newline at end of file
diff --git a/src/redux/actions.ts b/src/redux/actions.ts
index e69de29..aedb0d0 100644
--- a/src/redux/actions.ts
+++ b/src/redux/actions.ts
@@ -0,0 +1,23 @@
+const Item_Favourite = 'ITEM_FAVOURITE';
+const Item_Removed = 'ITEM_REMOVED';
+
+export type Action ={
+ type : string,
+ payload : string
+}
+
+function itemFavourite(src:string):Action{
+ return{
+ type : Item_Favourite,
+ payload : src
+ }
+}
+
+function itemRejected(src:string):Action{
+ return{
+ type : Item_Removed,
+ payload : src
+ }
+}
+
+export {itemFavourite,itemRejected,Item_Removed,Item_Favourite};
\ No newline at end of file
diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts
index be51d22..6e27844 100644
--- a/src/redux/reducer.ts
+++ b/src/redux/reducer.ts
@@ -1,6 +1,18 @@
-export const reducer = (initialState = {}, action) => {
+import { Item_Removed,Item_Favourite ,Action} from "./actions";
+
+type InitialState =string[]
+
+export const reducer = (initialState:InitialState=[] , action:Action) => {
switch (action.type) {
+
+ case Item_Favourite : return [...initialState,action.payload];
+
+ case Item_Removed :
+ let arr = initialState.filter((it) => it != action.payload);
+ return arr;
+
+
default:
return initialState
}
-}
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 2b88693..7d2000a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10214,10 +10214,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@^3.6.4:
- version "3.9.9"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
- integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
+typescript@4.5.4:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
+ integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
uglify-js@3.4.x:
version "3.4.10"