From bbd636943beb69a209a25dcadf5497caf1e05be5 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Fri, 8 Oct 2021 10:22:37 +0400
Subject: [PATCH 09/47] refactor: separate handler functions
---
src/components/News.tsx | 29 ++++++++++++++++-------------
src/types.ts | 4 ++++
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 3e5a9d3..72e08a0 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -42,17 +42,17 @@ function News() {
await refreshPageContent();
};
- const handleChange = (event: ChangeEvent,
- name?: string,
- param?: string | number) => {
- const { type, value } = event.target;
- if (name === 'pageSize') {
- setPageSize(Number(param as number));
- } else if (name === 'sortBy') {
- setSortBy(param as string);
- } else if (type === 'text') {
- setSearchValue(value);
- }
+ const handleSearchValueChange = (event: ChangeEvent) => {
+ const { value } = event.target;
+ setSearchValue(value);
+ };
+
+ const handlePageSizeChange = (value: number) => {
+ setPageSize(value);
+ };
+
+ const handleSortByChange = (value: string) => {
+ setSortBy(value);
};
const handleClick = async (event: MouseEventHandler) => {
@@ -88,6 +88,7 @@ function News() {
inputValue: string | number,
stateName: string,
stateValue: string | number,
+ handlerFunction, // : HandlePageSizeChange | HandleSortByChange,
) => (
@@ -105,7 +106,7 @@ function News() {
@@ -130,6 +132,7 @@ function News() {
element.inputValue,
'sortBy',
sortBy,
+ handleSortByChange,
))}
diff --git a/src/types.ts b/src/types.ts
index 851da36..70e6cbb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -8,3 +8,7 @@ export interface Article {
urlToImage: string;
url: string;
}
+
+// export type HandlerFunction = (value: number | string) => void;
+// export type HandleSortByChange = (value: string) => void;
+// export type HandlePageSizeChange = (value: number) => void;
From 793ce3da2f8be4582c57bd0051b4cb25fcfe4774 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Fri, 8 Oct 2021 15:59:02 +0400
Subject: [PATCH 10/47] feat: open dev server in chrome
---
webpack/webpack.dev.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/webpack/webpack.dev.js b/webpack/webpack.dev.js
index 08441cf..aac2059 100644
--- a/webpack/webpack.dev.js
+++ b/webpack/webpack.dev.js
@@ -3,6 +3,11 @@ module.exports = {
devtool: "cheap-module-source-map",
devServer: {
hot: true,
- open: true,
+ open: {
+ app: {
+ name: 'Google Chrome',
+ arguments: ['--incognito'],
+ }
+ },
}
}
From 17989ac7a4b707ca287761c3fba15e0ce69bab1c Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Fri, 8 Oct 2021 16:39:39 +0400
Subject: [PATCH 11/47] feat: add page counter, implement request with
async/await
---
src/components/News.tsx | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 72e08a0..6c026b2 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -11,6 +11,7 @@ function News() {
const [pageSize, setPageSize] = useState(10);
const [sortBy, setSortBy] = useState('publishedAt');
const [pageNum, setPageNum] = useState(1);
+ const [resultPages, setResultPages] = useState(0);
const refreshPageContent = async () => {
setIsLoading(true);
@@ -21,14 +22,11 @@ function News() {
+ `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
+ `&pageSize=${pageSize}&page=${pageNum}`;
const req = new Request(address);
- const result = await fetch(req)
- .then((response) => response.json())
- .then((data) => {
- setIsLoading(false);
- return data;
- });
- // console.log('result is: ', result.articles);
- setArticles(result.articles);
+ const result = await fetch(req);
+ const data = await result.json();
+ console.log('data: ', data);
+ setArticles(data.articles);
+ setResultPages(Math.floor(data.totalResults / pageSize));
} catch (e) {
console.error('error has occurred: ', e);
} finally {
@@ -139,6 +137,8 @@ function News() {
Page:
{pageNum}
+ {resultPages === 0 ? '' : ( of )}
+ {resultPages === 0 ? '' : (resultPages)}
);
diff --git a/src/types.ts b/src/types.ts
index 70e6cbb..bc6cbef 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -7,6 +7,14 @@ export interface Article {
title: string;
urlToImage: string;
url: string;
+ id: string;
+}
+
+export interface SearchParams {
+ searchValue: string;
+ pageSize: number;
+ sortBy: string;
+ pageNum: number;
}
// export type HandlerFunction = (value: number | string) => void;
From b13879a9c54180f189dd94ddfbdfd3d05b554caf Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 13:45:48 +0400
Subject: [PATCH 17/47] refactor: remove unnecessary variable
---
src/components/Details.tsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index 6ed4dbc..ab13a82 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -19,7 +19,6 @@ const loadDataFromApi = async (linkParamsObj) => {
// function return article object or object with title prop = 'not found';
const findArticle = (articles, articleId) => {
- const result = { title: 'Not found' };
const filteredArticles = articles.filter((article) => {
// transform url to id
const id = article.url
@@ -32,7 +31,7 @@ const findArticle = (articles, articleId) => {
}
});
if (filteredArticles.length === 0) {
- return result;
+ return { title: 'Not found' };
}
return filteredArticles[0];
};
From 622ecea6bb36eef2722128acbe21f72f517805a2 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 19:17:59 +0400
Subject: [PATCH 18/47] refactor: remove comments
---
src/components/Details.tsx | 1 -
src/components/News.tsx | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index ab13a82..124cf08 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -69,7 +69,6 @@ function Details() {
linkParamsStr.split('&').map((param) => {
const key = param.split('=')[0];
const value = param.split('=')[1];
- // console.log(key, value);
linkParamsObj[key] = value;
});
// get articles, found match, render info
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 7d55f76..05c814a 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -23,7 +23,6 @@ function News() {
const req = new Request(address);
const result = await fetch(req);
const data = await result.json();
- // console.log('data: ', data);
setArticles(data.articles);
setResultPages(Math.floor(data.totalResults / pageSize));
} catch (e) {
From fb4b0c5c8507732b628583e637949c801ff3cb72 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 20:33:14 +0400
Subject: [PATCH 19/47] refactor: rename component Page404 to PageNotFound
---
src/components/Header.tsx | 4 ++--
src/components/{Page404.tsx => PageNotFound.tsx} | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
rename src/components/{Page404.tsx => PageNotFound.tsx} (77%)
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 974dee2..9b50d44 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -8,7 +8,7 @@ import { useLocation } from 'react-router';
import { CSSTransition } from 'react-transition-group';
import News from './News';
import About from './About';
-import Page404 from './Page404';
+import PageNotFound from './PageNotFound';
import Details from './Details';
const routes = [
@@ -50,7 +50,7 @@ function RenderContent() {
} if (location.pathname !== '/' && location.pathname !== '/about') {
return (
);
}
diff --git a/src/components/Page404.tsx b/src/components/PageNotFound.tsx
similarity index 77%
rename from src/components/Page404.tsx
rename to src/components/PageNotFound.tsx
index a50dd1e..33d60e9 100644
--- a/src/components/Page404.tsx
+++ b/src/components/PageNotFound.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
-function Page404() {
+function PageNotFound() {
return (
Page not found
@@ -11,4 +11,4 @@ function Page404() {
);
}
-export default Page404;
+export default PageNotFound;
From 9105e5452c24743a04d36e1f5c7afd809742f4e0 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 20:34:05 +0400
Subject: [PATCH 20/47] refactor: rename PageNotFound to NotFoundPage
---
src/components/Header.tsx | 4 ++--
src/components/{PageNotFound.tsx => NotFoundPage.tsx} | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
rename src/components/{PageNotFound.tsx => NotFoundPage.tsx} (77%)
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 9b50d44..64c2dda 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -8,7 +8,7 @@ import { useLocation } from 'react-router';
import { CSSTransition } from 'react-transition-group';
import News from './News';
import About from './About';
-import PageNotFound from './PageNotFound';
+import NotFoundPage from './NotFoundPage';
import Details from './Details';
const routes = [
@@ -50,7 +50,7 @@ function RenderContent() {
} if (location.pathname !== '/' && location.pathname !== '/about') {
return (
);
}
diff --git a/src/components/PageNotFound.tsx b/src/components/NotFoundPage.tsx
similarity index 77%
rename from src/components/PageNotFound.tsx
rename to src/components/NotFoundPage.tsx
index 33d60e9..24172a1 100644
--- a/src/components/PageNotFound.tsx
+++ b/src/components/NotFoundPage.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
-function PageNotFound() {
+function NotFoundPage() {
return (
Page not found
@@ -11,4 +11,4 @@ function PageNotFound() {
);
}
-export default PageNotFound;
+export default NotFoundPage;
From e113f72219c8e92cd701a8ee64e1a786e1dc5ab7 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 20:42:24 +0400
Subject: [PATCH 21/47] refactor: remove nested ternary operator
---
src/components/Details.tsx | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index 124cf08..cff1423 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -39,10 +39,14 @@ const findArticle = (articles, articleId) => {
function RenderArticleData(props) {
const { data } = props;
const key = data[0];
- const value = (typeof data[1] === 'string')
- ? data[1] : (typeof data[1] !== 'object')
- ? 'null' : (data[1] === null)
- ? 'null' : data[1].name;
+ let value = '';
+ if (typeof data[1] === 'string') {
+ value = data[1].toString();
+ } else if (typeof data[1] === 'object' && data[1] !== null) {
+ value = data[1].name;
+ } else {
+ value = 'null';
+ }
return (
From e244443b348f59efc8b07323e6d16212ec037323 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sat, 23 Oct 2021 21:38:28 +0400
Subject: [PATCH 22/47] refactor: rewrite api request as helper function
---
src/components/Details.tsx | 31 ++++++++++++++++---------------
src/components/News.tsx | 27 ++++++++++++---------------
src/helpers.tsx | 26 ++++++++++++++++++++++++++
3 files changed, 54 insertions(+), 30 deletions(-)
create mode 100644 src/helpers.tsx
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index cff1423..53a4f25 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -1,21 +1,22 @@
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router';
-import { apiKey } from '../data';
+// import { apiKey } from '../data';
+import loadDataFromApi from '../helpers';
-const loadDataFromApi = async (linkParamsObj) => {
- const { searchValue, pageSize, sortBy } = linkParamsObj;
- try {
- const address = `https://newsapi.org/v2/everything?q=${searchValue}`
- + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
- + `&pageSize=${pageSize}`;
- const req = new Request(address);
- const result = await fetch(req);
- const data = await result.json();
- return data;
- } catch (e) {
- console.error('error has occurred: ', e);
- }
-};
+// const loadDataFromApi = async (linkParamsObj) => {
+// const { searchValue, pageSize, sortBy } = linkParamsObj;
+// try {
+// const address = `https://newsapi.org/v2/everything?q=${searchValue}`
+// + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
+// + `&pageSize=${pageSize}`;
+// const req = new Request(address);
+// const result = await fetch(req);
+// const data = await result.json();
+// return data;
+// } catch (e) {
+// console.error('error has occurred: ', e);
+// }
+// };
// function return article object or object with title prop = 'not found';
const findArticle = (articles, articleId) => {
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 05c814a..fc6fb4f 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -3,7 +3,8 @@ import React, {
} from 'react';
import { Article } from '../types';
import ArticleBox from './ArticleBox';
-import { pageSizeInputs, sortByInputs, apiKey } from '../data';
+import { pageSizeInputs, sortByInputs } from '../data';
+import loadDataFromApi from '../helpers';
function News() {
const [searchValue, setSearchValue] = useState('');
@@ -14,22 +15,18 @@ function News() {
const [pageNum, setPageNum] = useState(1);
const [resultPages, setResultPages] = useState(0);
+ const linkParameters = {
+ searchValue,
+ pageSize,
+ sortBy,
+ pageNum,
+ };
const refreshPageContent = async () => {
setIsLoading(true);
- try {
- const address = `https://newsapi.org/v2/everything?q=${searchValue}`
- + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
- + `&pageSize=${pageSize}&page=${pageNum}`;
- const req = new Request(address);
- const result = await fetch(req);
- const data = await result.json();
- setArticles(data.articles);
- setResultPages(Math.floor(data.totalResults / pageSize));
- } catch (e) {
- console.error('error has occurred: ', e);
- } finally {
- setIsLoading(false);
- }
+ const data = await loadDataFromApi(linkParameters);
+ setArticles(data.articles);
+ setResultPages(Math.floor(data.totalResults / pageSize));
+ setIsLoading(false);
};
const handleSubmit = async (event: ChangeEvent) => {
diff --git a/src/helpers.tsx b/src/helpers.tsx
new file mode 100644
index 0000000..8bcecad
--- /dev/null
+++ b/src/helpers.tsx
@@ -0,0 +1,26 @@
+import { apiKey } from './data';
+
+const loadDataFromApi = async (linkParamsObj) => {
+ const {
+ searchValue,
+ pageSize,
+ sortBy,
+ pageNum,
+ } = linkParamsObj;
+ try {
+ let address = `https://newsapi.org/v2/everything?q=${searchValue}`
+ + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
+ + `&pageSize=${pageSize}`;
+ if (pageNum !== undefined) {
+ address += `&page=${pageNum}`;
+ }
+ const req = new Request(address);
+ const result = await fetch(req);
+ return await result.json();
+ // return data;
+ } catch (e) {
+ console.error('error has occurred: ', e);
+ }
+};
+
+export default loadDataFromApi;
From 3abd34e0cba4b7321f94a720c6490ecc4588732c Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 24 Oct 2021 12:22:17 +0400
Subject: [PATCH 23/47] refactor: separate routing from header, routing
components
---
src/components/Header.tsx | 82 +--------------------
src/components/routing/RenderContent.tsx | 46 ++++++++++++
src/components/routing/RenderNavigation.tsx | 27 +++++++
src/components/routing/Routing.tsx | 24 ++++++
4 files changed, 99 insertions(+), 80 deletions(-)
create mode 100644 src/components/routing/RenderContent.tsx
create mode 100644 src/components/routing/RenderNavigation.tsx
create mode 100644 src/components/routing/Routing.tsx
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 64c2dda..d6935dc 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,87 +1,9 @@
import React from 'react';
-import {
- BrowserRouter as Router,
- Route,
- Link,
-} from 'react-router-dom';
-import { useLocation } from 'react-router';
-import { CSSTransition } from 'react-transition-group';
-import News from './News';
-import About from './About';
-import NotFoundPage from './NotFoundPage';
-import Details from './Details';
-
-const routes = [
- { path: '/', name: 'News', Component: News },
- { path: '/about', name: 'About', Component: About },
-];
-
-function RenderNavigation() {
- const location = useLocation();
- const path = location.pathname;
- return (
-
- );
-}
-
-function RenderContent() {
- const location = useLocation();
- if (location.pathname.split('/')[1] === 'details') {
- return (
-
- Element details:
- {'\n\n'}
-
-
- );
- } if (location.pathname !== '/' && location.pathname !== '/about') {
- return (
-
-
-
- );
- }
- return (
- routes.map(({ path, Component }) => (
-
- {({ match }) => (
-
-
-
-
-
- )}
-
- ))
- );
-}
+import Routing from './routing/Routing';
function Header() {
return (
-
-
-
-
+
);
}
diff --git a/src/components/routing/RenderContent.tsx b/src/components/routing/RenderContent.tsx
new file mode 100644
index 0000000..678818b
--- /dev/null
+++ b/src/components/routing/RenderContent.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { useLocation } from 'react-router';
+import { Route } from 'react-router-dom';
+import { CSSTransition } from 'react-transition-group';
+import Details from '../Details';
+import NotFoundPage from '../NotFoundPage';
+
+function RenderContent(props) {
+ const { routes } = props;
+ const location = useLocation();
+ if (location.pathname.split('/')[1] === 'details') {
+ return (
+
+ Element details:
+ {'\n\n'}
+
+
+ );
+ } if (location.pathname !== '/' && location.pathname !== '/about') {
+ return (
+
+
+
+ );
+ }
+ return (
+ routes.map(({ path, Component }) => (
+
+ {({ match }) => (
+
+
+
+
+
+ )}
+
+ ))
+ );
+}
+
+export default RenderContent;
diff --git a/src/components/routing/RenderNavigation.tsx b/src/components/routing/RenderNavigation.tsx
new file mode 100644
index 0000000..284692a
--- /dev/null
+++ b/src/components/routing/RenderNavigation.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { useLocation } from 'react-router';
+import { Link } from 'react-router-dom';
+
+function RenderNavigation(props) {
+ const { routes } = props;
+ const location = useLocation();
+ const path = location.pathname;
+ return (
+
+ );
+}
+
+export default RenderNavigation;
diff --git a/src/components/routing/Routing.tsx b/src/components/routing/Routing.tsx
new file mode 100644
index 0000000..7fa25ca
--- /dev/null
+++ b/src/components/routing/Routing.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { BrowserRouter as Router } from 'react-router-dom';
+import News from '../News';
+import About from '../About';
+import RenderNavigation from './RenderNavigation';
+import RenderContent from './RenderContent';
+
+const routes = [
+ { path: '/', name: 'News', Component: News },
+ { path: '/about', name: 'About', Component: About },
+];
+
+function Routing() {
+ return (
+
+
+
+
+ );
+}
+
+export default Routing;
From 8e5a03280d81fec5501e66a27a991f4c4c3fa830 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 24 Oct 2021 12:55:48 +0400
Subject: [PATCH 24/47] refactor: remove comments
---
src/components/Details.tsx | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index 53a4f25..e419139 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -1,23 +1,7 @@
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router';
-// import { apiKey } from '../data';
import loadDataFromApi from '../helpers';
-// const loadDataFromApi = async (linkParamsObj) => {
-// const { searchValue, pageSize, sortBy } = linkParamsObj;
-// try {
-// const address = `https://newsapi.org/v2/everything?q=${searchValue}`
-// + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
-// + `&pageSize=${pageSize}`;
-// const req = new Request(address);
-// const result = await fetch(req);
-// const data = await result.json();
-// return data;
-// } catch (e) {
-// console.error('error has occurred: ', e);
-// }
-// };
-
// function return article object or object with title prop = 'not found';
const findArticle = (articles, articleId) => {
const filteredArticles = articles.filter((article) => {
From 58bbafe8c94797b4425fef5a586d2070288d54d6 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 24 Oct 2021 17:01:13 +0400
Subject: [PATCH 25/47] refactor: implement RenderNavigation as ReactFC
---
src/components/routing/RenderNavigation.tsx | 36 ++++++++++-----------
src/components/routing/Routing.tsx | 7 +++-
2 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/src/components/routing/RenderNavigation.tsx b/src/components/routing/RenderNavigation.tsx
index 284692a..81e0b8c 100644
--- a/src/components/routing/RenderNavigation.tsx
+++ b/src/components/routing/RenderNavigation.tsx
@@ -1,27 +1,25 @@
-import React from 'react';
+import React, { FC } from 'react';
import { useLocation } from 'react-router';
import { Link } from 'react-router-dom';
-function RenderNavigation(props) {
- const { routes } = props;
+interface RoutesListItem {
+ path: string,
+ name: string,
+}
+
+const RenderNavigation: FC = ({ path, name }) => {
const location = useLocation();
- const path = location.pathname;
+ const browserPath = location.pathname;
return (
-
+
+
+ {name}
+
+
);
-}
+};
export default RenderNavigation;
diff --git a/src/components/routing/Routing.tsx b/src/components/routing/Routing.tsx
index 7fa25ca..1af33ad 100644
--- a/src/components/routing/Routing.tsx
+++ b/src/components/routing/Routing.tsx
@@ -14,7 +14,12 @@ function Routing() {
return (
From ba92f2b2920666105a0b7b36f35d6c4b7d278ff9 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 24 Oct 2021 20:27:52 +0400
Subject: [PATCH 26/47] refactor: implement RenderContent as ReactFC
---
src/components/routing/RenderContent.tsx | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/components/routing/RenderContent.tsx b/src/components/routing/RenderContent.tsx
index 678818b..9ac0400 100644
--- a/src/components/routing/RenderContent.tsx
+++ b/src/components/routing/RenderContent.tsx
@@ -1,14 +1,26 @@
-import React from 'react';
+import React, { FC } from 'react';
import { useLocation } from 'react-router';
import { Route } from 'react-router-dom';
import { CSSTransition } from 'react-transition-group';
import Details from '../Details';
import NotFoundPage from '../NotFoundPage';
-function RenderContent(props) {
+interface RoutesListItem {
+ path: string,
+ name: string,
+ Component: FC,
+}
+type RoutesListType = RoutesListItem[];
+
+type RoutesListObj = {
+ routes: RoutesListType;
+};
+
+const RenderContent: FC = (props: RoutesListObj) => {
const { routes } = props;
const location = useLocation();
- if (location.pathname.split('/')[1] === 'details') {
+ const browserPath = location.pathname;
+ if (browserPath.split('/')[1] === 'details') {
return (
Element details:
@@ -16,7 +28,7 @@ function RenderContent(props) {
);
- } if (location.pathname !== '/' && location.pathname !== '/about') {
+ } if (browserPath !== '/' && browserPath !== '/about') {
return (
@@ -41,6 +53,6 @@ function RenderContent(props) {
))
);
-}
+};
export default RenderContent;
From 742d60d3df4ed3e4e40df457ab8b911124963a67 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 24 Oct 2021 23:11:15 +0400
Subject: [PATCH 27/47] refactor: pass renderPageSizeInput parameters as object
---
src/components/News.tsx | 81 +++++++++++++++++++++++++----------------
1 file changed, 49 insertions(+), 32 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index fc6fb4f..e645cce 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -65,25 +65,35 @@ function News() {
}
}, [pageNum, pageSize, sortBy]);
- const renderPageSizeInput = (
+ type InputParams = {
inputID: string,
inputName: string,
inputValue: string | number,
- stateName: string,
stateValue: string | number,
- handlerFunction, // : HandlePageSizeChange | HandleSortByChange,
- ) => (
-
- );
+ handlerFunction,
+ };
+
+ const renderPageSizeInput = (params: InputParams) => {
+ const {
+ inputID,
+ inputName,
+ inputValue,
+ stateValue,
+ handlerFunction,
+ } = params;
+ return (
+
+ );
+ };
return (
@@ -98,25 +108,31 @@ function News() {
News per page:
- {pageSizeInputs.map((element) => renderPageSizeInput(
- element.inputID,
- element.inputName,
- element.inputValue,
- 'pageSize',
- pageSize,
- handlePageSizeChange,
- ))}
+ {pageSizeInputs.map((element) => {
+ const params = {
+ inputID: element.inputID,
+ inputName: element.inputName,
+ inputValue: element.inputValue,
+ stateName: 'pageSize',
+ stateValue: pageSize,
+ handlerFunction: handlePageSizeChange,
+ };
+ return renderPageSizeInput(params);
+ })}
Sort news by:
- {sortByInputs.map((element) => renderPageSizeInput(
- element.inputID,
- element.inputName,
- element.inputValue,
- 'sortBy',
- sortBy,
- handleSortByChange,
- ))}
+ {sortByInputs.map((element) => {
+ const params = {
+ inputID: element.inputID,
+ inputName: element.inputName,
+ inputValue: element.inputValue,
+ stateName: 'sortBy',
+ stateValue: sortBy,
+ handlerFunction: handleSortByChange,
+ };
+ return renderPageSizeInput(params);
+ })}
@@ -152,7 +168,8 @@ function News() {
sortBy,
pageNum,
}}
- />))}
+ />
+ ))}
);
From 49d56d89459a69dc42e074394e7a57700e67de76 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Mon, 25 Oct 2021 12:02:03 +0400
Subject: [PATCH 28/47] refactor: move condition from useEffect to function
---
src/components/News.tsx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index e645cce..debe80d 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -23,9 +23,11 @@ function News() {
};
const refreshPageContent = async () => {
setIsLoading(true);
- const data = await loadDataFromApi(linkParameters);
- setArticles(data.articles);
- setResultPages(Math.floor(data.totalResults / pageSize));
+ if (searchValue !== '') {
+ const data = await loadDataFromApi(linkParameters);
+ setArticles(data.articles);
+ setResultPages(Math.floor(data.totalResults / pageSize));
+ }
setIsLoading(false);
};
@@ -60,9 +62,7 @@ function News() {
};
useEffect(() => {
- if (searchValue !== '') {
- refreshPageContent();
- }
+ refreshPageContent();
}, [pageNum, pageSize, sortBy]);
type InputParams = {
From a12c304623e5a9f6b4a1e74fbd8b8d1b514d1cc9 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Tue, 26 Oct 2021 12:44:19 +0400
Subject: [PATCH 29/47] fix: move flag set under condition
---
src/components/News.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index debe80d..e14529a 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -22,13 +22,13 @@ function News() {
pageNum,
};
const refreshPageContent = async () => {
- setIsLoading(true);
if (searchValue !== '') {
+ setIsLoading(true);
const data = await loadDataFromApi(linkParameters);
setArticles(data.articles);
setResultPages(Math.floor(data.totalResults / pageSize));
+ setIsLoading(false);
}
- setIsLoading(false);
};
const handleSubmit = async (event: ChangeEvent) => {
From 4ae1b05bfca1190fe6949667ec6d8e19d0ba3598 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Fri, 29 Oct 2021 21:16:01 +0400
Subject: [PATCH 30/47] fix: provide case for empty search value fix: provide
case for empty search value fix: fix total number of news calculation fix:
searchValue and value of search field are separated fix: disable -next-
button on empty page refactor: few cosmetic details refactor: remove
unnecessary types
---
src/components/ArticleBox.tsx | 11 ++++-
src/components/News.tsx | 63 +++++++++++++++---------
src/components/routing/RenderContent.tsx | 9 ++--
src/helpers.tsx | 38 +++++++++-----
4 files changed, 79 insertions(+), 42 deletions(-)
diff --git a/src/components/ArticleBox.tsx b/src/components/ArticleBox.tsx
index a1a0358..f898fe5 100644
--- a/src/components/ArticleBox.tsx
+++ b/src/components/ArticleBox.tsx
@@ -2,8 +2,8 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { Article, SearchParams } from '../types';
-function ArticleBox(props: { data: Article, searchParams: SearchParams }) {
- const { data, searchParams } = props;
+function ArticleBox(props: { data: Article, searchParams: SearchParams, totalResults: number }) {
+ const { data, searchParams, totalResults } = props;
const {
author,
url,
@@ -22,6 +22,13 @@ function ArticleBox(props: { data: Article, searchParams: SearchParams }) {
.split('')
.filter((char) => /:|\.|\/|%|-|\?/.test(char) ? '' : char)
.join('');
+ if ((searchValue === '' || source.name === 'snf') && totalResults === 0) {
+ return (
+
+
please provide search value
+
+ );
+ }
return (
{title}
diff --git a/src/components/News.tsx b/src/components/News.tsx
index e14529a..14b70d2 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -1,5 +1,5 @@
import React, {
- ChangeEvent, MouseEventHandler, useEffect, useState,
+ ChangeEvent, MouseEventHandler, useCallback, useEffect, useState,
} from 'react';
import { Article } from '../types';
import ArticleBox from './ArticleBox';
@@ -8,38 +8,39 @@ import loadDataFromApi from '../helpers';
function News() {
const [searchValue, setSearchValue] = useState
('');
+ const [searchFieldValue, setSearchFieldValue] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [articles, setArticles] = useState([]);
+ const [searchResultsCounter, setSearchResultsCounter] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [sortBy, setSortBy] = useState('publishedAt');
const [pageNum, setPageNum] = useState(1);
const [resultPages, setResultPages] = useState(0);
- const linkParameters = {
- searchValue,
- pageSize,
- sortBy,
- pageNum,
- };
- const refreshPageContent = async () => {
- if (searchValue !== '') {
- setIsLoading(true);
- const data = await loadDataFromApi(linkParameters);
- setArticles(data.articles);
- setResultPages(Math.floor(data.totalResults / pageSize));
- setIsLoading(false);
- }
- };
+ const updatePageContent = useCallback(async () => {
+ setIsLoading(true);
+ const data = await loadDataFromApi({
+ searchValue,
+ pageNum,
+ pageSize,
+ sortBy,
+ });
+ setArticles(data.articles);
+ setSearchResultsCounter(data.totalResults);
+ setResultPages(Math.floor(data.totalResults / pageSize));
+ setIsLoading(false);
+ }, [searchValue, pageNum, pageSize, sortBy]);
const handleSubmit = async (event: ChangeEvent) => {
event.preventDefault();
setPageNum(1);
- await refreshPageContent();
+ setSearchValue(searchFieldValue);
+ await updatePageContent();
};
const handleSearchValueChange = (event: ChangeEvent) => {
const { value } = event.target;
- setSearchValue(value);
+ setSearchFieldValue(value);
};
const handlePageSizeChange = (value: number) => {
@@ -54,16 +55,16 @@ function News() {
const { name } = event.target;
if (name === 'prev') {
setPageNum((currentPageNumber) => currentPageNumber - 1);
- await refreshPageContent();
+ await updatePageContent();
} else if (name === 'next') {
setPageNum((currentPageNumber) => currentPageNumber + 1);
- await refreshPageContent();
+ await updatePageContent();
}
};
useEffect(() => {
- refreshPageContent();
- }, [pageNum, pageSize, sortBy]);
+ updatePageContent();
+ }, [updatePageContent]);
type InputParams = {
inputID: string,
@@ -99,7 +100,14 @@ function News() {
@@ -122,7 +136,7 @@ function News() {
inputName: element.inputName,
inputValue: element.inputValue,
stateName: 'pageSize',
- stateValue: pageSize,
+ stateValue: feedParameters.pageSize,
handlerFunction: handlePageSizeChange,
};
return renderPageSizeInput(params);
@@ -136,7 +150,7 @@ function News() {
inputName: element.inputName,
inputValue: element.inputValue,
stateName: 'sortBy',
- stateValue: sortBy,
+ stateValue: feedParameters.sortBy,
handlerFunction: handleSortByChange,
};
return renderPageSizeInput(params);
@@ -145,47 +159,33 @@ function News() {
Page:
- {pageNum}
- {resultPages === 0 ? '' : ( of )}
- {resultPages === 0 ? '' : (resultPages)}
+ {feedParameters.pageNum}
+ {feedParameters.feed.totalResults === 0 ? '' : ( of )}
+ {feedParameters.feed.totalResults === 0 ? '' : (Math.floor(feedParameters.feed.totalResults / feedParameters.pageSize))}
-
- {articles.map((element) => (
-
- ))}
-
+
);
}
diff --git a/src/features/feedParameters/Feed.tsx b/src/features/feedParameters/Feed.tsx
new file mode 100644
index 0000000..a1e6758
--- /dev/null
+++ b/src/features/feedParameters/Feed.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { selectFeedParameters } from './feedParametersSlice';
+import ArticleBox from '../../components/ArticleBox';
+
+function Feed() {
+ const feedParameters = useSelector(selectFeedParameters);
+ const {
+ searchValue,
+ pageSize,
+ sortBy,
+ pageNum,
+ status,
+ } = feedParameters;
+ const { totalResults, articles } = feedParameters.feed;
+ if (status === 'loading') {
+ return (
+
+ Loading
+
+ );
+ } if (totalResults === 0 && searchValue === '') {
+ return (
+
+ Please provide search value
+
+ );
+ } if (totalResults === 0) {
+ return (
+
+ Nothing found on request "
+ { searchValue }
+ "
+
+ );
+ }
+ return (
+
+ {articles.map((element) => (
+
+ ))}
+
+ );
+}
+
+export default Feed;
diff --git a/src/features/feedParameters/feedParametersSlice.tsx b/src/features/feedParameters/feedParametersSlice.tsx
new file mode 100644
index 0000000..6957755
--- /dev/null
+++ b/src/features/feedParameters/feedParametersSlice.tsx
@@ -0,0 +1,83 @@
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+import loadDataFromApi, { Args } from '../../helpers';
+
+const initialState = {
+ searchValue: '',
+ pageSize: 10,
+ sortBy: 'publishedAt',
+ pageNum: 1,
+ status: 'idle',
+ feed: {
+ totalResults: 0,
+ articles: [],
+ },
+};
+
+export const requestFeedFromAPI = createAsyncThunk(
+ 'feedParameters/fetchFeed',
+ async (arg: Args) => {
+ const response = await loadDataFromApi(arg);
+ return response;
+ },
+);
+
+export const feedParametersSlice = createSlice({
+ name: 'feedParameters',
+ initialState,
+ reducers: {
+ setSearchValueS: (state, action) => {
+ return {
+ ...state,
+ searchValue: action.payload,
+ };
+ },
+ setPageSizeS: (state, action) => {
+ return {
+ ...state,
+ pageSize: action.payload,
+ };
+ },
+ setSortByS: (state, action) => {
+ return {
+ ...state,
+ sortBy: action.payload,
+ };
+ },
+ setPageNumS: (state, action) => {
+ return {
+ ...state,
+ pageNum: action.payload,
+ };
+ },
+ },
+ extraReducers: (builder) => {
+ builder
+ .addCase(requestFeedFromAPI.pending, (state) => {
+ return {
+ ...state,
+ status: 'loading',
+ };
+ })
+ .addCase(requestFeedFromAPI.fulfilled, (state, action) => {
+ return {
+ ...state,
+ status: 'idle',
+ feed: action.payload,
+ };
+ })
+ .addCase(requestFeedFromAPI.rejected, (state) => {
+ return {
+ ...state,
+ status: 'idle',
+ };
+ });
+ },
+});
+
+export const {
+ setSearchValueS, setPageSizeS, setSortByS, setPageNumS,
+} = feedParametersSlice.actions;
+
+export const selectFeedParameters = (state) => state.feedParameters;
+
+export default feedParametersSlice.reducer;
diff --git a/src/helpers.tsx b/src/helpers.tsx
index 4cec6fd..6a2c959 100644
--- a/src/helpers.tsx
+++ b/src/helpers.tsx
@@ -1,6 +1,6 @@
import { apiKey } from './data';
-interface Args {
+export interface Args {
searchValue: string,
pageSize: number,
sortBy: string,
@@ -17,7 +17,7 @@ const loadDataFromApi = async (args: Args) => {
try {
if (searchValue !== '') {
let address = `https://newsapi.org/v2/everything?q=${searchValue}`
- + `&from=2021-10-02&sortBy=${sortBy}&apiKey=${apiKey}`
+ + `&from=2021-10-15&sortBy=${sortBy}&apiKey=${apiKey}`
+ `&pageSize=${pageSize}`;
if (pageNum !== undefined) {
address += `&page=${pageNum}`;
@@ -31,11 +31,7 @@ const loadDataFromApi = async (args: Args) => {
}
return {
totalResults: 0,
- articles: [{
- title: 'request is empty',
- url: 'this value used as unique id',
- source: { id: null, name: 'snf' },
- }],
+ articles: [],
};
};
From 79d437b41999f5f3196a41f42e372cda62a940fd Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Sun, 7 Nov 2021 19:32:22 +0400
Subject: [PATCH 32/47] refactor: rename files
---
src/app/store.tsx | 2 +-
src/components/About.tsx | 4 ++--
src/components/News.tsx | 8 ++++----
src/features/{feedParameters => feed}/Feed.tsx | 2 +-
.../feedParametersSlice.tsx => feed/feedSlice.tsx} | 8 ++++----
5 files changed, 12 insertions(+), 12 deletions(-)
rename src/features/{feedParameters => feed}/Feed.tsx (94%)
rename src/features/{feedParameters/feedParametersSlice.tsx => feed/feedSlice.tsx} (91%)
diff --git a/src/app/store.tsx b/src/app/store.tsx
index 0654e28..6cd3ae3 100644
--- a/src/app/store.tsx
+++ b/src/app/store.tsx
@@ -1,5 +1,5 @@
import { configureStore } from '@reduxjs/toolkit';
-import feedParametersReducer from '../features/feedParameters/feedParametersSlice';
+import feedParametersReducer from '../features/feed/feedSlice';
export default configureStore({
reducer: {
diff --git a/src/components/About.tsx b/src/components/About.tsx
index c83e570..e2450b7 100644
--- a/src/components/About.tsx
+++ b/src/components/About.tsx
@@ -1,12 +1,12 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { selectFeedParameters, setPageSizeS } from '../features/feedParameters/feedParametersSlice';
+import { selectFeedParameters, setPageSizeS } from '../features/feed/feedSlice';
function About() {
// store test
const feedParameters = useSelector(selectFeedParameters);
const dispatch = useDispatch();
- // console.log(feedParameters);
+ // console.log(feed);
return (
This is 'about' page
diff --git a/src/components/News.tsx b/src/components/News.tsx
index a5e9da9..85190be 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -10,8 +10,8 @@ import {
setPageNumS,
setSearchValueS,
requestFeedFromAPI,
-} from '../features/feedParameters/feedParametersSlice';
-import Feed from '../features/feedParameters/Feed';
+} from '../features/feed/feedSlice';
+import Feed from '../features/feed/Feed';
function News() {
const feedParameters = useSelector(selectFeedParameters);
@@ -22,8 +22,8 @@ function News() {
event.preventDefault();
dispatch(setSearchValueS(searchFieldValue));
dispatch(setPageNumS(1));
- // console.log('will search with searchValue: ', searchFieldValue, feedParameters.searchValue);
- // console.log('current args: ', feedParameters);
+ // console.log('will search with searchValue: ', searchFieldValue, feed.searchValue);
+ // console.log('current args: ', feed);
const linkArgs = {
...feedParameters,
searchValue: searchFieldValue,
diff --git a/src/features/feedParameters/Feed.tsx b/src/features/feed/Feed.tsx
similarity index 94%
rename from src/features/feedParameters/Feed.tsx
rename to src/features/feed/Feed.tsx
index a1e6758..df94270 100644
--- a/src/features/feedParameters/Feed.tsx
+++ b/src/features/feed/Feed.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { useSelector } from 'react-redux';
-import { selectFeedParameters } from './feedParametersSlice';
+import { selectFeedParameters } from './feedSlice';
import ArticleBox from '../../components/ArticleBox';
function Feed() {
diff --git a/src/features/feedParameters/feedParametersSlice.tsx b/src/features/feed/feedSlice.tsx
similarity index 91%
rename from src/features/feedParameters/feedParametersSlice.tsx
rename to src/features/feed/feedSlice.tsx
index 6957755..adfae3b 100644
--- a/src/features/feedParameters/feedParametersSlice.tsx
+++ b/src/features/feed/feedSlice.tsx
@@ -14,14 +14,14 @@ const initialState = {
};
export const requestFeedFromAPI = createAsyncThunk(
- 'feedParameters/fetchFeed',
+ 'feed/fetchFeed',
async (arg: Args) => {
const response = await loadDataFromApi(arg);
return response;
},
);
-export const feedParametersSlice = createSlice({
+export const feedSlice = createSlice({
name: 'feedParameters',
initialState,
reducers: {
@@ -76,8 +76,8 @@ export const feedParametersSlice = createSlice({
export const {
setSearchValueS, setPageSizeS, setSortByS, setPageNumS,
-} = feedParametersSlice.actions;
+} = feedSlice.actions;
export const selectFeedParameters = (state) => state.feedParameters;
-export default feedParametersSlice.reducer;
+export default feedSlice.reducer;
From 497378c24693e6f7b690c2339af9919ba1731d46 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Thu, 11 Nov 2021 11:01:35 +0400
Subject: [PATCH 33/47] refactor: Details component refactor - add types, split
functionality, use react-router api, etc
---
src/components/Article.tsx | 54 +++++++++++++++++++
src/components/ArticleBox.tsx | 4 +-
src/components/Details.tsx | 98 ++++++++++++++++-------------------
src/helpers.tsx | 1 +
4 files changed, 103 insertions(+), 54 deletions(-)
create mode 100644 src/components/Article.tsx
diff --git a/src/components/Article.tsx b/src/components/Article.tsx
new file mode 100644
index 0000000..18c533a
--- /dev/null
+++ b/src/components/Article.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+
+export interface ArticleInfo {
+ title: string,
+ author?: string,
+ description?: string,
+ url?: string,
+ content?: string,
+ publishedAt?: string,
+ source?: {id: null | string, name: null | string}
+ urlToImage?: string,
+}
+
+interface Props {
+ data: ArticleInfo
+}
+
+function objFlatter(obj: {[index: string]:any}, prefix = ''): object {
+ console.log(obj);
+ const result: {[index: string]:any} = {};
+ const keys = Object.keys(obj);
+ keys.forEach((key) => {
+ if (typeof (obj[key]) === 'object' && !!obj[key]) {
+ Object.assign(result, objFlatter(obj[key], `${key}-`));
+ } else {
+ const newKey = prefix + key;
+ result[newKey] = obj[key];
+ }
+ });
+ return result;
+}
+
+function Article(props: Props) {
+ const { data } = props;
+ const articleData = Object.entries(objFlatter(data));
+ return (
+
+ Article details:
+ {articleData.map((element) => {
+ const propKey = element[0];
+ const propValue = element[1];
+ return (
+
+ {propKey}
+ {' : '}
+ {String(propValue)}
+
+ );
+ })}
+
+ );
+}
+
+export default Article;
diff --git a/src/components/ArticleBox.tsx b/src/components/ArticleBox.tsx
index c81a4fa..b92b9cb 100644
--- a/src/components/ArticleBox.tsx
+++ b/src/components/ArticleBox.tsx
@@ -20,7 +20,7 @@ function ArticleBox(props: { data: Article, searchParams: SearchParams, totalRes
const date = new Date(publishedAt);
const id = url
.split('')
- .filter((char) => /:|\.|\/|%|-|\?/.test(char) ? '' : char)
+ .filter((char) => (/:|\.|\/|%|-|\?/.test(char) ? '' : char))
.join('');
if ((searchValue === '' || source.name === 'snf') && totalResults === 0) {
return (
@@ -45,7 +45,7 @@ function ArticleBox(props: { data: Article, searchParams: SearchParams, totalRes
- Details
+ Details
);
}
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index e419139..901e2fc 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -1,87 +1,81 @@
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { useLocation } from 'react-router';
-import loadDataFromApi from '../helpers';
+import loadDataFromApi, { Args } from '../helpers';
+import Article, { ArticleInfo } from './Article';
+
+function useQuery() {
+ const { search } = useLocation();
+ return React.useMemo(() => new URLSearchParams(search), [search]);
+}
+
+interface ArticleItem1 {
+ title: string,
+ author: string,
+ description: string,
+ url: string,
+ content: string,
+ publishedAt: string,
+ source: {id: null | string, name: null | string}
+ urlToImage: string,
+}
// function return article object or object with title prop = 'not found';
-const findArticle = (articles, articleId) => {
+const findArticle = (articles: ArticleItem1[], articleId: string | undefined) => {
const filteredArticles = articles.filter((article) => {
// transform url to id
const id = article.url
.split('')
- .filter((symbol: string) => /:|\.|\/|%|-|\?/.test(symbol) ? '' : symbol)
+ .filter((symbol: string) => (/:|\.|\/|%|-|\?/.test(symbol) ? '' : symbol))
.join('');
// check for match
if (id === articleId) {
return article;
}
+ return false;
});
- if (filteredArticles.length === 0) {
+ if (!filteredArticles.length) {
return { title: 'Not found' };
}
return filteredArticles[0];
};
-function RenderArticleData(props) {
- const { data } = props;
- const key = data[0];
- let value = '';
- if (typeof data[1] === 'string') {
- value = data[1].toString();
- } else if (typeof data[1] === 'object' && data[1] !== null) {
- value = data[1].name;
- } else {
- value = 'null';
- }
- return (
-
-
- {key}
- {': '}
-
- {value}
-
- );
-}
-
function Details() {
- const [result, setResult] = useState({ title: 'Loading...' });
- // disassemble link and get params
- const location = useLocation();
- const path = location.pathname;
- const linkParamsStr = path.split('/')[2];
- const linkParamsObj = {
+ const [result, setResult] = useState(null);
+ // START REFACTOR
+ // get params from link
+ const linkParams: Args = {
searchValue: '',
pageSize: 100,
sortBy: 'publishedAt',
id: '',
};
- linkParamsStr.split('&').map((param) => {
- const key = param.split('=')[0];
- const value = param.split('=')[1];
- linkParamsObj[key] = value;
+ const query = useQuery();
+ const queryParams = ['searchValue', 'sortBy', 'id'];
+ queryParams.forEach((element) => {
+ linkParams[element] = query.get(element);
});
- // get articles, found match, render info
+ // request news and look for match
const getResult = async () => {
// get last 100 news from api
- const data = await loadDataFromApi(linkParamsObj);
+ const data = await loadDataFromApi(linkParams);
// filter articles
- const filteredArticle = findArticle(data.articles, linkParamsObj.id);
+ const filteredArticle = findArticle(data.articles, linkParams.id);
setResult(filteredArticle);
};
- // useEffect to refresh result
- useEffect(() => {
- if (result.title === 'Loading...') {
- getResult();
- }
- }, []);
- const articleData = Object.entries(result);
+ if (!result) {
+ getResult();
+ }
+ // console.log(result);
+ if (!!result && result.title === 'Not found') {
+ return (
+
+ Not found
+
+ );
+ }
return (
- {articleData.map((element) => {
- return (
-
- );
- })}
+ {result ?
: 'Loading...'}
);
}
diff --git a/src/helpers.tsx b/src/helpers.tsx
index 6a2c959..ee8d2ca 100644
--- a/src/helpers.tsx
+++ b/src/helpers.tsx
@@ -5,6 +5,7 @@ export interface Args {
pageSize: number,
sortBy: string,
pageNum?: number,
+ id?: string
}
const loadDataFromApi = async (args: Args) => {
From 6ed3e08f936d90a9896a7a7289cf12e6e469ec6a Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Thu, 11 Nov 2021 12:16:21 +0400
Subject: [PATCH 34/47] refactor: deprecate Header component, move Router to
App
---
src/App.tsx | 4 ++--
src/components/Header.tsx | 10 ----------
2 files changed, 2 insertions(+), 12 deletions(-)
delete mode 100644 src/components/Header.tsx
diff --git a/src/App.tsx b/src/App.tsx
index 11bd01e..8ff964a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,14 +1,14 @@
import React from 'react';
import './App.css';
-import Header from './components/Header';
import { Provider } from 'react-redux';
import store from './app/store';
+import Routing from './components/routing/Routing';
const App = () => (
News search engine
-
+
);
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
deleted file mode 100644
index d6935dc..0000000
--- a/src/components/Header.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-import Routing from './routing/Routing';
-
-function Header() {
- return (
-
- );
-}
-
-export default Header;
From dfa530ef4c707475fb9912e5725b333c539399e0 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Thu, 11 Nov 2021 12:26:18 +0400
Subject: [PATCH 35/47] refactor: remove comments, fix variables naming
---
src/components/About.tsx | 12 ------------
src/components/Article.tsx | 1 -
src/components/Details.tsx | 1 -
src/components/News.tsx | 26 ++++++++++++--------------
src/features/feed/feedSlice.tsx | 10 +++++-----
5 files changed, 17 insertions(+), 33 deletions(-)
diff --git a/src/components/About.tsx b/src/components/About.tsx
index e2450b7..2d1b59b 100644
--- a/src/components/About.tsx
+++ b/src/components/About.tsx
@@ -1,12 +1,6 @@
import React from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { selectFeedParameters, setPageSizeS } from '../features/feed/feedSlice';
function About() {
- // store test
- const feedParameters = useSelector(selectFeedParameters);
- const dispatch = useDispatch();
- // console.log(feed);
return (
This is 'about' page
@@ -19,12 +13,6 @@ function About() {
Aenean tempus gravida nulla, eget cursus augue accumsan id.
Aliquam in tempor mi, a sagittis quam.
-
- Pagesize:
- {feedParameters.pageSize}
-
-
-
);
}
diff --git a/src/components/Article.tsx b/src/components/Article.tsx
index 18c533a..5eebcc9 100644
--- a/src/components/Article.tsx
+++ b/src/components/Article.tsx
@@ -16,7 +16,6 @@ interface Props {
}
function objFlatter(obj: {[index: string]:any}, prefix = ''): object {
- console.log(obj);
const result: {[index: string]:any} = {};
const keys = Object.keys(obj);
keys.forEach((key) => {
diff --git a/src/components/Details.tsx b/src/components/Details.tsx
index 901e2fc..36051a6 100644
--- a/src/components/Details.tsx
+++ b/src/components/Details.tsx
@@ -65,7 +65,6 @@ function Details() {
if (!result) {
getResult();
}
- // console.log(result);
if (!!result && result.title === 'Not found') {
return (
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 85190be..ea2dfeb 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -5,10 +5,10 @@ import { useDispatch, useSelector } from 'react-redux';
import { pageSizeInputs, sortByInputs } from '../data';
import {
selectFeedParameters,
- setPageSizeS,
- setSortByS,
- setPageNumS,
- setSearchValueS,
+ setPageSize,
+ setSortBy,
+ setPageNum,
+ setSearchValue,
requestFeedFromAPI,
} from '../features/feed/feedSlice';
import Feed from '../features/feed/Feed';
@@ -20,10 +20,8 @@ function News() {
const handleSubmit = async (event: ChangeEvent
) => {
event.preventDefault();
- dispatch(setSearchValueS(searchFieldValue));
- dispatch(setPageNumS(1));
- // console.log('will search with searchValue: ', searchFieldValue, feed.searchValue);
- // console.log('current args: ', feed);
+ dispatch(setSearchValue(searchFieldValue));
+ dispatch(setPageNum(1));
const linkArgs = {
...feedParameters,
searchValue: searchFieldValue,
@@ -38,8 +36,8 @@ function News() {
};
const handlePageSizeChange = (value: number) => {
- dispatch(setPageSizeS(value));
- dispatch(setPageNumS(1));
+ dispatch(setPageSize(value));
+ dispatch(setPageNum(1));
const linkArgs = {
...feedParameters,
pageSize: value,
@@ -49,8 +47,8 @@ function News() {
};
const handleSortByChange = (value: string) => {
- dispatch(setSortByS(value));
- dispatch(setPageNumS(1));
+ dispatch(setSortBy(value));
+ dispatch(setPageNum(1));
const linkArgs = {
...feedParameters,
sortBy: value,
@@ -63,7 +61,7 @@ function News() {
const { name } = event.target;
if (name === 'prev') {
const newPageNum = feedParameters.pageNum - 1;
- dispatch(setPageNumS(newPageNum));
+ dispatch(setPageNum(newPageNum));
const linkArgs = {
...feedParameters,
pageNum: newPageNum,
@@ -71,7 +69,7 @@ function News() {
dispatch(requestFeedFromAPI(linkArgs));
} else if (name === 'next') {
const newPageNum = feedParameters.pageNum + 1;
- dispatch(setPageNumS(newPageNum));
+ dispatch(setPageNum(newPageNum));
const linkArgs = {
...feedParameters,
pageNum: newPageNum,
diff --git a/src/features/feed/feedSlice.tsx b/src/features/feed/feedSlice.tsx
index adfae3b..708ebe7 100644
--- a/src/features/feed/feedSlice.tsx
+++ b/src/features/feed/feedSlice.tsx
@@ -25,25 +25,25 @@ export const feedSlice = createSlice({
name: 'feedParameters',
initialState,
reducers: {
- setSearchValueS: (state, action) => {
+ setSearchValue: (state, action) => {
return {
...state,
searchValue: action.payload,
};
},
- setPageSizeS: (state, action) => {
+ setPageSize: (state, action) => {
return {
...state,
pageSize: action.payload,
};
},
- setSortByS: (state, action) => {
+ setSortBy: (state, action) => {
return {
...state,
sortBy: action.payload,
};
},
- setPageNumS: (state, action) => {
+ setPageNum: (state, action) => {
return {
...state,
pageNum: action.payload,
@@ -75,7 +75,7 @@ export const feedSlice = createSlice({
});
export const {
- setSearchValueS, setPageSizeS, setSortByS, setPageNumS,
+ setSearchValue, setPageSize, setSortBy, setPageNum,
} = feedSlice.actions;
export const selectFeedParameters = (state) => state.feedParameters;
From b598428123bb57f4d7f030259016589d9f65df30 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Thu, 11 Nov 2021 12:32:39 +0400
Subject: [PATCH 36/47] fix: change type to interface, add variable validation
---
src/components/News.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/News.tsx b/src/components/News.tsx
index ea2dfeb..e2c6e52 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -78,13 +78,13 @@ function News() {
}
};
- type InputParams = {
+ interface InputParams {
inputID: string,
inputName: string,
inputValue: string | number,
stateValue: string | number,
- handlerFunction,
- };
+ handlerFunction: Function,
+ }
const renderPageSizeInput = (params: InputParams) => {
const {
From cbcd261e67b7e6859eb5fa8a60c7cc99a4cf9134 Mon Sep 17 00:00:00 2001
From: prokhorovd
Date: Thu, 11 Nov 2021 12:49:09 +0400
Subject: [PATCH 37/47] refactor: convert flag from string to boolean, small
syntax fixes
---
src/components/ArticleBox.tsx | 2 +-
src/components/News.tsx | 14 +++++++-------
src/features/feed/Feed.tsx | 4 ++--
src/features/feed/feedSlice.tsx | 8 ++++----
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/components/ArticleBox.tsx b/src/components/ArticleBox.tsx
index b92b9cb..52a6c59 100644
--- a/src/components/ArticleBox.tsx
+++ b/src/components/ArticleBox.tsx
@@ -22,7 +22,7 @@ function ArticleBox(props: { data: Article, searchParams: SearchParams, totalRes
.split('')
.filter((char) => (/:|\.|\/|%|-|\?/.test(char) ? '' : char))
.join('');
- if ((searchValue === '' || source.name === 'snf') && totalResults === 0) {
+ if ((!!searchValue || source.name === 'snf') && totalResults === 0) {
return (
please provide search value!!
diff --git a/src/components/News.tsx b/src/components/News.tsx
index e2c6e52..2aa46c0 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -102,7 +102,7 @@ function News() {
id={inputID}
checked={stateValue === inputValue}
onChange={() => handlerFunction(inputValue)}
- disabled={feedParameters.status === 'loading'}
+ disabled={feedParameters.isLoading}
/>
);
@@ -118,11 +118,11 @@ function News() {
placeholder="I'm looking for..."
value={searchFieldValue}
onChange={handleSearchValueChange}
- disabled={feedParameters.status === 'loading'}
+ disabled={feedParameters.isLoading}
/>
-