diff --git a/.env b/.env
new file mode 100644
index 0000000..c8eafc4
--- /dev/null
+++ b/.env
@@ -0,0 +1,2 @@
+REACT_APP_API_ENDPOINT=https://api.openweathermap.org/data/2.5/
+REACT_APP_KEY = 623949ba087cb249c44a770ad1a293fe
\ No newline at end of file
diff --git a/package.json b/package.json
index 6917922..667a8f2 100644
--- a/package.json
+++ b/package.json
@@ -14,10 +14,12 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/uuid": "^8.3.4",
+ "axios": "^0.27.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
+ "url-join": "^5.0.0",
"uuid": "^9.0.0",
"web-vitals": "^2.1.0"
},
diff --git a/src/App.tsx b/src/App.tsx
index 1e363c0..e030407 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,8 @@
import './App.css';
-function App() {
+function App() {
+
+
return (
diff --git a/src/api/index.ts b/src/api/index.ts
new file mode 100644
index 0000000..502a1ea
--- /dev/null
+++ b/src/api/index.ts
@@ -0,0 +1,8 @@
+/* eslint-disable import/no-anonymous-default-export */
+import API from '../utils/constants/api';
+import RestService from '../utils/service/api';
+
+export default {
+ // EXAMPLE: Your need delete it
+ // weather: new RestService(API.WEATHER),
+};
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 6431bc5..9534e83 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1 +1,8 @@
///
+declare namespace NodeJS {
+ interface ProcessEnv {
+ //types of envs
+ NODE_ENV: "development" | "production" | "test";
+ PUBLIC_URL: string;
+ }
+}
diff --git a/src/utils/constants/api.ts b/src/utils/constants/api.ts
new file mode 100644
index 0000000..63e6341
--- /dev/null
+++ b/src/utils/constants/api.ts
@@ -0,0 +1,9 @@
+export enum API_STATUS {
+ HTTP_404_NOT_FOUND = 400,
+ HTTP_500_SERVER = 500,
+}
+
+//TODO: you need delete when integrate API
+// export default {
+// WEATHER: 'weather',
+// };
diff --git a/src/utils/reducer/api-reducer.ts b/src/utils/reducer/api-reducer.ts
new file mode 100644
index 0000000..e472c97
--- /dev/null
+++ b/src/utils/reducer/api-reducer.ts
@@ -0,0 +1,41 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+export const INITIAL_STATE: InfoApi = {
+ isLoading: false,
+ isError: false,
+ data: null,
+ errorMsg: '',
+};
+
+export enum ACTION_TYPE {
+ FETCH_START = 'START',
+ FETCH_SUCCESS = 'SUCCESS',
+ FETCH_FAILED = 'FAILED',
+}
+
+export const apiReducer = (state: InfoApi, action: ActionReducer) => {
+ switch (action.type) {
+ case ACTION_TYPE.FETCH_START:
+ return {
+ ...state,
+ isLoading: true,
+ isError: false,
+ };
+ case ACTION_TYPE.FETCH_SUCCESS:
+ return {
+ isLoading: false,
+ isError: false,
+ data: action.payload,
+ };
+
+ case ACTION_TYPE.FETCH_FAILED:
+ return {
+ ...state,
+ isLoading: false,
+ isError: true,
+ errorMsg: action.errorMsg,
+ };
+
+ default:
+ return INITIAL_STATE;
+ }
+};
diff --git a/src/utils/service/api.ts b/src/utils/service/api.ts
new file mode 100644
index 0000000..7d4ddc7
--- /dev/null
+++ b/src/utils/service/api.ts
@@ -0,0 +1,36 @@
+import axios, { AxiosError, AxiosResponse } from 'axios';
+import urlJoin from 'url-join';
+import { API_STATUS } from '../constants/api';
+
+const baseURL = process.env.REACT_APP_API_ENDPOINT || '';
+
+const linkApi = (resource: string) => {
+ return urlJoin(baseURL, resource);
+};
+
+const handleError = (error: AxiosError) => {
+ if (!error.response?.status || [API_STATUS.HTTP_500_SERVER].includes(error.response?.status)) {
+ console.log(error.response);
+ } else {
+ return error.response.data;
+ }
+};
+
+class RestService {
+ constructor(protected resource: string) {}
+
+ index(params?: R) {
+ return new Promise>((resolve, rejects) => {
+ axios
+ .get(linkApi(this.resource), {
+ params,
+ })
+ .then(resolve)
+ .catch((error: AxiosError) => {
+ rejects(handleError(error));
+ });
+ });
+ }
+}
+
+export default RestService;
diff --git a/src/utils/types/api.d.ts b/src/utils/types/api.d.ts
new file mode 100644
index 0000000..8356150
--- /dev/null
+++ b/src/utils/types/api.d.ts
@@ -0,0 +1,12 @@
+interface InfoApi {
+ isLoading: boolean;
+ data?: any;
+ isError: boolean;
+ errorMsg?: string;
+}
+
+interface ActionReducer {
+ type: string;
+ payload?: ApiResponse;
+ errorMsg?: string;
+}
diff --git a/yarn.lock b/yarn.lock
index 39f37fc..97d0cc6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2862,6 +2862,14 @@ axe-core@^4.4.3:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==
+axios@^0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
+ integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
+ dependencies:
+ follow-redirects "^1.14.9"
+ form-data "^4.0.0"
+
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -4637,7 +4645,7 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
-follow-redirects@^1.0.0:
+follow-redirects@^1.0.0, follow-redirects@^1.14.9:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@@ -4670,6 +4678,15 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -8765,6 +8782,11 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
+url-join@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-5.0.0.tgz#c2f1e5cbd95fa91082a93b58a1f42fecb4bdbcf1"
+ integrity sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==
+
url-parse@^1.5.3:
version "1.5.10"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"