diff --git a/.env.example b/.env.example index 46011f0..9082189 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ -REACT_APP_API_KEY = "" -REACT_APP_API_URL = "https://newsapi.org/v2/" \ No newline at end of file +NEXT_PUBLIC_API_KEY = "" +NEXT_PUBLIC_API_URL = "https://newsapi.org/v2/" diff --git a/.gitignore b/.gitignore index cc964cb..0201ceb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - +.next # dependencies /node_modules /.pnp diff --git a/README.md b/README.md index b370586..1f6d738 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ In this ABlOG Project project we have the following sections done: ## Technologies Used -This project is mainly based on [React.js](https://reactjs.org/) plus others few libraries listed below: +This project is mainly based on [Next.js](https://nextjs.org/) plus others few libraries listed below: - [Tailwind css](https://tailwindcss.com/) - [redux](https://www.npmjs.com/package/redux) diff --git a/src/components/layout/Header.jsx b/components/layout/Header.jsx similarity index 79% rename from src/components/layout/Header.jsx rename to components/layout/Header.jsx index f937e70..568da21 100644 --- a/src/components/layout/Header.jsx +++ b/components/layout/Header.jsx @@ -1,15 +1,15 @@ -import { Link } from "react-router-dom"; +import Link from "next/link"; export default function Header() { return (
- + A BlOG
+ headlines ? state.headlines : state.articles + ); + return ( + <> + {data.isError && } +
+ {data.isLoading ? ( + + ) : ( + data.value?.map((article, index) => { + return ; + }) + )} +
+ + {data.value?.length === 0 && } + + ); +} diff --git a/components/sections/homepage/NavSkeleton.jsx b/components/sections/homepage/NavSkeleton.jsx new file mode 100644 index 0000000..2878670 --- /dev/null +++ b/components/sections/homepage/NavSkeleton.jsx @@ -0,0 +1,7 @@ +import Skeleton from "react-loading-skeleton"; + +export default function NavSkeleton({ count }) { + return Array(count) + .fill() + .map((_, index) => ); +} diff --git a/src/components/sections/homepage/Navigation.jsx b/components/sections/homepage/Navigation.jsx similarity index 66% rename from src/components/sections/homepage/Navigation.jsx rename to components/sections/homepage/Navigation.jsx index b97eb9c..e5ac09e 100644 --- a/src/components/sections/homepage/Navigation.jsx +++ b/components/sections/homepage/Navigation.jsx @@ -1,30 +1,25 @@ import { useState } from "react"; -import { useGetPublisherQuery } from "../../../services/publishersApi"; -import Skeleton from "react-loading-skeleton"; import SearchInput from "../../ui/SearchInput"; import Slider from "react-slick"; import settings from "../../../config/reactSlickSetting"; -import { Link } from "react-router-dom"; +import { useSelector } from "react-redux"; +import Link from "next/link"; +import NavSkeleton from "./NavSkeleton"; export default function Navigation() { - const { data: publishers, isLoading } = useGetPublisherQuery(); + const navigationTab = useSelector((state) => state.publishers); const [whichTab, setWhichTab] = useState(""); return (
- {isLoading === true ? ( - Array(5) - .fill() - .map((value, index) => ( - - )) + {navigationTab.isLoading ? ( + ) : ( - {publishers?.sources.map((item) => ( + {navigationTab.value?.map((item) => ( )} + {navigationTab.isError &&

Opps.. something went wrong

}
diff --git a/components/ui/Card/Skeleton.jsx b/components/ui/Card/Skeleton.jsx new file mode 100644 index 0000000..9c0d27f --- /dev/null +++ b/components/ui/Card/Skeleton.jsx @@ -0,0 +1,22 @@ +import Skeleton from "react-loading-skeleton"; + +export default function CardSkeleton({ count }) { + return ( + <> + {Array(count) + .fill() + .map((_, index) => { + return ( +
+ +
+ + +
+ +
+ ); + })} + + ); +} diff --git a/src/components/ui/Card.jsx b/components/ui/Card/index.jsx similarity index 77% rename from src/components/ui/Card.jsx rename to components/ui/Card/index.jsx index e53bf46..4261bed 100644 --- a/src/components/ui/Card.jsx +++ b/components/ui/Card/index.jsx @@ -1,11 +1,10 @@ -import { Link } from "react-router-dom"; -import getDateTime from "../../utils/getDateTime"; - +import Link from "next/link"; +import getDateTime from "../../../utils/getDateTime"; export default function Card({ article }) { - const { title, urlToImage, publishedAt } = article; + const { title, urlToImage, publishedAt, url } = article; const date = new Date(publishedAt); return ( - +
+
{search.length > 0 && (
- { return (state = action.payload); diff --git a/features/headlines.js b/features/headlines.js new file mode 100644 index 0000000..da64a66 --- /dev/null +++ b/features/headlines.js @@ -0,0 +1,36 @@ +import { createSlice } from "@reduxjs/toolkit"; +const headlinesSlice = createSlice({ + name: "headlines", + initialState: { + value: [], + backupValues: [], + isError: false, + isLoading: true, + }, + reducers: { + setHeadlines: (state, action) => { + return (state = action.payload); + }, + searchHeadlines: (state, action) => { + const { value } = action.payload; + const { backupValues } = state; + if (value === "") { + return { + ...state, + value: backupValues, + }; + } + const filteredHeadlines = backupValues.filter((headline) => { + const { title } = headline; + return title.toLowerCase().includes(value.toLowerCase()); + }); + return { + ...state, + value: filteredHeadlines, + }; + }, + }, +}); + +export const { setHeadlines, searchHeadlines } = headlinesSlice.actions; +export default headlinesSlice.reducer; diff --git a/features/publishers.js b/features/publishers.js new file mode 100644 index 0000000..7232ebe --- /dev/null +++ b/features/publishers.js @@ -0,0 +1,26 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { HYDRATE } from "next-redux-wrapper"; +const publishersSlice = createSlice({ + name: "publishers", + initialState: { + value: [], + isError: false, + isLoading: true, + }, + reducers: { + setPublishers: (state, action) => { + return (state = action.payload); + }, + }, + extraReducers: { + [HYDRATE]: (state, action) => { + return { + ...state, + ...action.payload.auth, + }; + }, + }, +}); + +export const { setPublishers } = publishersSlice.actions; +export default publishersSlice.reducer; diff --git a/package-lock.json b/package-lock.json index 5976c38..3c7959f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,8 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "next": "^13.2.4", + "next-redux-wrapper": "^8.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-feather": "^2.0.10", @@ -26,6 +28,8 @@ "web-vitals": "^2.1.4" }, "devDependencies": { + "autoprefixer": "^10.4.14", + "postcss": "^8.4.21", "tailwindcss": "^3.2.7" } }, @@ -3016,6 +3020,206 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "node_modules/@next/env": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.2.4.tgz", + "integrity": "sha512-+Mq3TtpkeeKFZanPturjcXt+KHfKYnLlX6jMLyCrmpq6OOs4i1GqBOAauSkii9QeKCMTYzGppar21JU57b/GEA==" + }, + "node_modules/@next/swc-android-arm-eabi": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.4.tgz", + "integrity": "sha512-DWlalTSkLjDU11MY11jg17O1gGQzpRccM9Oes2yTqj2DpHndajrXHGxj9HGtJ+idq2k7ImUdJVWS2h2l/EDJOw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-android-arm64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.4.tgz", + "integrity": "sha512-sRavmUImUCf332Gy+PjIfLkMhiRX1Ez4SI+3vFDRs1N5eXp+uNzjFUK/oLMMOzk6KFSkbiK/3Wt8+dHQR/flNg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.4.tgz", + "integrity": "sha512-S6vBl+OrInP47TM3LlYx65betocKUUlTZDDKzTiRDbsRESeyIkBtZ6Qi5uT2zQs4imqllJznVjFd1bXLx3Aa6A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.4.tgz", + "integrity": "sha512-a6LBuoYGcFOPGd4o8TPo7wmv5FnMr+Prz+vYHopEDuhDoMSHOnC+v+Ab4D7F0NMZkvQjEJQdJS3rqgFhlZmKlw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-freebsd-x64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.4.tgz", + "integrity": "sha512-kkbzKVZGPaXRBPisoAQkh3xh22r+TD+5HwoC5bOkALraJ0dsOQgSMAvzMXKsN3tMzJUPS0tjtRf1cTzrQ0I5vQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm-gnueabihf": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.4.tgz", + "integrity": "sha512-7qA1++UY0fjprqtjBZaOA6cas/7GekpjVsZn/0uHvquuITFCdKGFCsKNBx3S0Rpxmx6WYo0GcmhNRM9ru08BGg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.4.tgz", + "integrity": "sha512-xzYZdAeq883MwXgcwc72hqo/F/dwUxCukpDOkx/j1HTq/J0wJthMGjinN9wH5bPR98Mfeh1MZJ91WWPnZOedOg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.4.tgz", + "integrity": "sha512-8rXr3WfmqSiYkb71qzuDP6I6R2T2tpkmf83elDN8z783N9nvTJf2E7eLx86wu2OJCi4T05nuxCsh4IOU3LQ5xw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.4.tgz", + "integrity": "sha512-Ngxh51zGSlYJ4EfpKG4LI6WfquulNdtmHg1yuOYlaAr33KyPJp4HeN/tivBnAHcZkoNy0hh/SbwDyCnz5PFJQQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.4.tgz", + "integrity": "sha512-gOvwIYoSxd+j14LOcvJr+ekd9fwYT1RyMAHOp7znA10+l40wkFiMONPLWiZuHxfRk+Dy7YdNdDh3ImumvL6VwA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.4.tgz", + "integrity": "sha512-q3NJzcfClgBm4HvdcnoEncmztxrA5GXqKeiZ/hADvC56pwNALt3ngDC6t6qr1YW9V/EPDxCYeaX4zYxHciW4Dw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.4.tgz", + "integrity": "sha512-/eZ5ncmHUYtD2fc6EUmAIZlAJnVT2YmxDsKs1Ourx0ttTtvtma/WKlMV5NoUsyOez0f9ExLyOpeCoz5aj+MPXw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.4.tgz", + "integrity": "sha512-0MffFmyv7tBLlji01qc0IaPP/LVExzvj7/R5x1Jph1bTAIj4Vu81yFQWHHQAP6r4ff9Ukj1mBK6MDNVXm7Tcvw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3474,6 +3678,14 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@tailwindcss/line-clamp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", @@ -5839,6 +6051,11 @@ "node": ">=0.10.0" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -12253,6 +12470,94 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/next": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-13.2.4.tgz", + "integrity": "sha512-g1I30317cThkEpvzfXujf0O4wtaQHtDCLhlivwlTJ885Ld+eOgcz7r3TGQzeU+cSRoNHtD8tsJgzxVdYojFssw==", + "dependencies": { + "@next/env": "13.2.4", + "@swc/helpers": "0.4.14", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=14.6.0" + }, + "optionalDependencies": { + "@next/swc-android-arm-eabi": "13.2.4", + "@next/swc-android-arm64": "13.2.4", + "@next/swc-darwin-arm64": "13.2.4", + "@next/swc-darwin-x64": "13.2.4", + "@next/swc-freebsd-x64": "13.2.4", + "@next/swc-linux-arm-gnueabihf": "13.2.4", + "@next/swc-linux-arm64-gnu": "13.2.4", + "@next/swc-linux-arm64-musl": "13.2.4", + "@next/swc-linux-x64-gnu": "13.2.4", + "@next/swc-linux-x64-musl": "13.2.4", + "@next/swc-win32-arm64-msvc": "13.2.4", + "@next/swc-win32-ia32-msvc": "13.2.4", + "@next/swc-win32-x64-msvc": "13.2.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.4.0", + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-redux-wrapper": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/next-redux-wrapper/-/next-redux-wrapper-8.1.0.tgz", + "integrity": "sha512-2hIau0hcI6uQszOtrvAFqgc0NkZegKYhBB7ZAKiG3jk7zfuQb4E7OV9jfxViqqojh3SEHdnFfPkN9KErttUKuw==", + "peerDependencies": { + "next": ">=9", + "react": "*", + "react-redux": "*" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -15770,6 +16075,28 @@ "webpack": "^5.0.0" } }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -19483,6 +19810,89 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "@next/env": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.2.4.tgz", + "integrity": "sha512-+Mq3TtpkeeKFZanPturjcXt+KHfKYnLlX6jMLyCrmpq6OOs4i1GqBOAauSkii9QeKCMTYzGppar21JU57b/GEA==" + }, + "@next/swc-android-arm-eabi": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.4.tgz", + "integrity": "sha512-DWlalTSkLjDU11MY11jg17O1gGQzpRccM9Oes2yTqj2DpHndajrXHGxj9HGtJ+idq2k7ImUdJVWS2h2l/EDJOw==", + "optional": true + }, + "@next/swc-android-arm64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.4.tgz", + "integrity": "sha512-sRavmUImUCf332Gy+PjIfLkMhiRX1Ez4SI+3vFDRs1N5eXp+uNzjFUK/oLMMOzk6KFSkbiK/3Wt8+dHQR/flNg==", + "optional": true + }, + "@next/swc-darwin-arm64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.4.tgz", + "integrity": "sha512-S6vBl+OrInP47TM3LlYx65betocKUUlTZDDKzTiRDbsRESeyIkBtZ6Qi5uT2zQs4imqllJznVjFd1bXLx3Aa6A==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.4.tgz", + "integrity": "sha512-a6LBuoYGcFOPGd4o8TPo7wmv5FnMr+Prz+vYHopEDuhDoMSHOnC+v+Ab4D7F0NMZkvQjEJQdJS3rqgFhlZmKlw==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.4.tgz", + "integrity": "sha512-kkbzKVZGPaXRBPisoAQkh3xh22r+TD+5HwoC5bOkALraJ0dsOQgSMAvzMXKsN3tMzJUPS0tjtRf1cTzrQ0I5vQ==", + "optional": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.4.tgz", + "integrity": "sha512-7qA1++UY0fjprqtjBZaOA6cas/7GekpjVsZn/0uHvquuITFCdKGFCsKNBx3S0Rpxmx6WYo0GcmhNRM9ru08BGg==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.4.tgz", + "integrity": "sha512-xzYZdAeq883MwXgcwc72hqo/F/dwUxCukpDOkx/j1HTq/J0wJthMGjinN9wH5bPR98Mfeh1MZJ91WWPnZOedOg==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.4.tgz", + "integrity": "sha512-8rXr3WfmqSiYkb71qzuDP6I6R2T2tpkmf83elDN8z783N9nvTJf2E7eLx86wu2OJCi4T05nuxCsh4IOU3LQ5xw==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.4.tgz", + "integrity": "sha512-Ngxh51zGSlYJ4EfpKG4LI6WfquulNdtmHg1yuOYlaAr33KyPJp4HeN/tivBnAHcZkoNy0hh/SbwDyCnz5PFJQQ==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.4.tgz", + "integrity": "sha512-gOvwIYoSxd+j14LOcvJr+ekd9fwYT1RyMAHOp7znA10+l40wkFiMONPLWiZuHxfRk+Dy7YdNdDh3ImumvL6VwA==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.4.tgz", + "integrity": "sha512-q3NJzcfClgBm4HvdcnoEncmztxrA5GXqKeiZ/hADvC56pwNALt3ngDC6t6qr1YW9V/EPDxCYeaX4zYxHciW4Dw==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.4.tgz", + "integrity": "sha512-/eZ5ncmHUYtD2fc6EUmAIZlAJnVT2YmxDsKs1Ourx0ttTtvtma/WKlMV5NoUsyOez0f9ExLyOpeCoz5aj+MPXw==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.4.tgz", + "integrity": "sha512-0MffFmyv7tBLlji01qc0IaPP/LVExzvj7/R5x1Jph1bTAIj4Vu81yFQWHHQAP6r4ff9Ukj1mBK6MDNVXm7Tcvw==", + "optional": true + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -19756,6 +20166,14 @@ "loader-utils": "^2.0.0" } }, + "@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "requires": { + "tslib": "^2.4.0" + } + }, "@tailwindcss/line-clamp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", @@ -21572,6 +21990,11 @@ } } }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -26235,6 +26658,49 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "next": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-13.2.4.tgz", + "integrity": "sha512-g1I30317cThkEpvzfXujf0O4wtaQHtDCLhlivwlTJ885Ld+eOgcz7r3TGQzeU+cSRoNHtD8tsJgzxVdYojFssw==", + "requires": { + "@next/env": "13.2.4", + "@next/swc-android-arm-eabi": "13.2.4", + "@next/swc-android-arm64": "13.2.4", + "@next/swc-darwin-arm64": "13.2.4", + "@next/swc-darwin-x64": "13.2.4", + "@next/swc-freebsd-x64": "13.2.4", + "@next/swc-linux-arm-gnueabihf": "13.2.4", + "@next/swc-linux-arm64-gnu": "13.2.4", + "@next/swc-linux-arm64-musl": "13.2.4", + "@next/swc-linux-x64-gnu": "13.2.4", + "@next/swc-linux-x64-musl": "13.2.4", + "@next/swc-win32-arm64-msvc": "13.2.4", + "@next/swc-win32-ia32-msvc": "13.2.4", + "@next/swc-win32-x64-msvc": "13.2.4", + "@swc/helpers": "0.4.14", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + }, + "dependencies": { + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + } + } + }, + "next-redux-wrapper": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/next-redux-wrapper/-/next-redux-wrapper-8.1.0.tgz", + "integrity": "sha512-2hIau0hcI6uQszOtrvAFqgc0NkZegKYhBB7ZAKiG3jk7zfuQb4E7OV9jfxViqqojh3SEHdnFfPkN9KErttUKuw==", + "requires": {} + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -28592,6 +29058,14 @@ "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", "requires": {} }, + "styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "requires": { + "client-only": "0.0.1" + } + }, "stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", diff --git a/package.json b/package.json index 4cd4512..e8d0727 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "next": "^13.2.4", + "next-redux-wrapper": "^8.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-feather": "^2.0.10", @@ -16,16 +18,15 @@ "react-router-dom": "^6.9.0", "react-scripts": "5.0.1", "react-slick": "^0.29.0", - "react-snapshot": "^1.3.0", "redux": "^4.2.1", "slick-carousel": "^1.8.1", "web-vitals": "^2.1.4" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" }, "eslintConfig": { "extends": [ @@ -46,6 +47,8 @@ ] }, "devDependencies": { + "autoprefixer": "^10.4.14", + "postcss": "^8.4.21", "tailwindcss": "^3.2.7" } } diff --git a/pages/_app.jsx b/pages/_app.jsx new file mode 100644 index 0000000..1db1894 --- /dev/null +++ b/pages/_app.jsx @@ -0,0 +1,28 @@ +import "../styles/globals.css"; +import "slick-carousel/slick/slick.css"; +import "slick-carousel/slick/slick-theme.css"; +import "react-loading-skeleton/dist/skeleton.css"; +import { wrapper } from "../store"; +import Header from "../components/layout/Header"; +import Head from "next/head"; +function App({ Component, pageProps }) { + return ( + <> + + ABLOG + + + + +
+
+ +
+ + ); +} + +export default wrapper.withRedux(App); diff --git a/pages/index.jsx b/pages/index.jsx new file mode 100644 index 0000000..cc61000 --- /dev/null +++ b/pages/index.jsx @@ -0,0 +1,46 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import Navigation from "../components/sections/homepage/Navigation"; +import { setPublishers } from "../features/publishers"; +import { publishersApi } from "../services/publishersApi"; +import { articlesApi } from "../services/articlesApi"; +import { setHeadlines } from "../features/headlines"; +import Blog from "../components/sections/Blog"; + +export default function Home({ publishers, blogList }) { + const dispatch = useDispatch(); + useEffect(() => { + dispatch( + setPublishers({ + value: publishers.sources, + isError: publishers.status === "ok" ? false : true, + isLoading: false, + }) + ); + dispatch( + setHeadlines({ + value: blogList.articles, + backupValues: blogList.articles, + isError: blogList.status === "ok" ? false : true, + isLoading: false, + }) + ); + }, [dispatch, publishers, blogList]); + return ( +
+ + +
+ ); +} + +export async function getStaticProps() { + const publishers = await publishersApi(); + const articles = await articlesApi("headlines"); + return { + props: { + publishers: publishers, + blogList: articles, + }, + }; +} diff --git a/pages/news/[id].jsx b/pages/news/[id].jsx new file mode 100644 index 0000000..d5bc281 --- /dev/null +++ b/pages/news/[id].jsx @@ -0,0 +1,39 @@ +import Link from "next/link"; +import { useEffect } from "react"; +import { ArrowLeft } from "react-feather"; +import { useDispatch } from "react-redux"; +import Blog from "../../components/sections/Blog"; +import { setArticles } from "../../features/articles"; +import { articlesApi } from "../../services/articlesApi"; + +export default function Articles({ blogList }) { + const dispatch = useDispatch(); + useEffect(() => { + dispatch( + setArticles({ + value: blogList.articles, + isError: blogList.status === "ok" ? false : true, + isLoading: false, + }) + ); + }, [dispatch, blogList]); + return ( +
+ + + Back + + +
+ ); +} + +export async function getServerSideProps(context) { + const { id } = context.params; + const articles = await articlesApi(id); + return { + props: { + blogList: articles, + }, + }; +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/services/articlesApi.js b/services/articlesApi.js new file mode 100644 index 0000000..3d5790c --- /dev/null +++ b/services/articlesApi.js @@ -0,0 +1,15 @@ +const { NEXT_PUBLIC_API_KEY, NEXT_PUBLIC_API_URL } = process.env; +const headers = { + "X-Api-Key": NEXT_PUBLIC_API_KEY, +}; +export const articlesApi = async (publisher) => { + const getTypeUrl = + publisher === "headlines" + ? `top-headlines?country=us&pageSize=10` + : `top-headlines?sources=${publisher}&pageSize=10`; + const response = await fetch(NEXT_PUBLIC_API_URL + getTypeUrl, { + headers, + }); + const data = await response.json(); + return data; +}; diff --git a/services/publishersApi.js b/services/publishersApi.js new file mode 100644 index 0000000..759df0d --- /dev/null +++ b/services/publishersApi.js @@ -0,0 +1,14 @@ +const { NEXT_PUBLIC_API_KEY, NEXT_PUBLIC_API_URL } = process.env; +const headers = { + "X-Api-Key": NEXT_PUBLIC_API_KEY, +}; +export const publishersApi = async () => { + const response = await fetch( + `${NEXT_PUBLIC_API_URL}top-headlines/sources?country=us`, + { + headers, + } + ); + const data = await response.json(); + return data; +}; diff --git a/src/App.jsx b/src/App.jsx deleted file mode 100644 index d9f2bbc..0000000 --- a/src/App.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Route, Routes } from "react-router-dom"; -import Article from "./pages/Article"; -import Articles from "./pages/Articles"; -import Home from "./pages/Home"; - -export default function App() { - return ( - - } /> - } /> - } /> - - ); -} diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/components/sections/articlespage/Blog.jsx b/src/components/sections/articlespage/Blog.jsx deleted file mode 100644 index f254d7d..0000000 --- a/src/components/sections/articlespage/Blog.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useGetArticlesQuery } from "../../../services/articlesApi"; -import Card from "../../ui/Card"; -import CardSkeleton from "../../ui/CardSkeleton"; -import ErrorFound from "../../ui/ErrorFound"; -import NotFound from "../../ui/NotFound"; - -export default function Blog({ whichTab }) { - const { data, isError, isLoading } = useGetArticlesQuery(whichTab); - - return ( - <> - {isError && } -
- {isLoading - ? Array(10) - .fill() - .map((v, k) => { - return ; - }) - : data.map((article, index) => { - return ; - })} -
- - {data?.length === 0 && } - - ); -} diff --git a/src/components/sections/homepage/Blog.jsx b/src/components/sections/homepage/Blog.jsx deleted file mode 100644 index 5f9ff8e..0000000 --- a/src/components/sections/homepage/Blog.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { setArticles } from "../../../features/articles"; -import { useGetArticlesQuery } from "../../../services/articlesApi"; -import Card from "../../ui/Card"; -import CardSkeleton from "../../ui/CardSkeleton"; -import ErrorFound from "../../ui/ErrorFound"; -import NotFound from "../../ui/NotFound"; - -export default function Blog() { - const { - data: headlines, - isLoading, - isError, - } = useGetArticlesQuery("headlines"); - const dispatch = useDispatch(); - const data = useSelector((state) => state.articles); - useEffect(() => { - if (headlines) { - dispatch(setArticles(headlines)); - } - }, [dispatch, headlines]); - - return ( - <> - {isError && } -
- {isLoading - ? Array(10) - .fill() - .map((v, k) => { - return ; - }) - : data.map((article, index) => { - return ; - })} -
- {data?.length === 0 && } - - ); -} diff --git a/src/components/ui/CardSkeleton.jsx b/src/components/ui/CardSkeleton.jsx deleted file mode 100644 index 59987f1..0000000 --- a/src/components/ui/CardSkeleton.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import Skeleton from "react-loading-skeleton"; - -export default function CardSkeleton() { - return ( -
- -
- - -
- -
- ); -} diff --git a/src/components/wrappers/PageWrapper.jsx b/src/components/wrappers/PageWrapper.jsx deleted file mode 100644 index fa45839..0000000 --- a/src/components/wrappers/PageWrapper.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import Header from "../layout/Header"; - -const PageWrapper = ({ children }) => { - return ( -
-
- {children} -
- ); -}; - -export default PageWrapper; diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 510a87d..0000000 --- a/src/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import "react-loading-skeleton/dist/skeleton.css"; -import App from "./App"; -import reportWebVitals from "./reportWebVitals"; -import { Provider } from "react-redux"; -import store from "./store"; -import PageWrapper from "./components/wrappers/PageWrapper"; -import "./index.css"; -import "slick-carousel/slick/slick.css"; -import "slick-carousel/slick/slick-theme.css"; -import { BrowserRouter } from "react-router-dom"; -const root = ReactDOM.createRoot(document.getElementById("root")); -root.render( - - - - - - - - - -); -reportWebVitals(); diff --git a/src/pages/Article.jsx b/src/pages/Article.jsx deleted file mode 100644 index 50ee68e..0000000 --- a/src/pages/Article.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useLocation } from "react-router-dom"; -import getDateTime from "../utils/getDateTime"; - -export default function Article() { - const { state } = useLocation(); - const date = new Date(state.publishedAt); - return ( -
-
-

{state.title}

-

{state.description}

-
-

{state.source.name}

-
- {getDateTime(date.getMonth(), date.getDay())} - - {date.getMinutes()} min -
-
- - - -
-
- {state.title} -
-
- ); -} diff --git a/src/pages/Articles.jsx b/src/pages/Articles.jsx deleted file mode 100644 index 79c2d40..0000000 --- a/src/pages/Articles.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import { ArrowLeft } from "react-feather"; -import { Link, useLocation } from "react-router-dom"; -import Blog from "../components/sections/articlespage/Blog"; - -export default function Articles() { - const { state } = useLocation(); - return ( -
- - - Back - - -
- ); -} diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx deleted file mode 100644 index 7a56c0c..0000000 --- a/src/pages/Home.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import Blog from "../components/sections/homepage/Blog"; -import Navigation from "../components/sections/homepage/Navigation"; -export default function Home() { - return ( -
- - -
- ); -} diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3a..0000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/services/articlesApi.js b/src/services/articlesApi.js deleted file mode 100644 index 02d40f3..0000000 --- a/src/services/articlesApi.js +++ /dev/null @@ -1,31 +0,0 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; -export const articlesApi = createApi({ - reducerPath: "articlesApi", - baseQuery: fetchBaseQuery({ - baseUrl: REACT_APP_API_URL, - headers: { - "X-Api-Key": REACT_APP_API_KEY, - }, - }), - - endpoints: (builder) => ({ - getArticles: builder.query({ - query: (publisher) => { - if (publisher) { - return publisher === "headlines" - ? `top-headlines?country=us&pageSize=10` - : `top-headlines?sources=${publisher}&pageSize=10`; - } - }, - transformResponse: (response) => response.articles, - }), - searchArticles: builder.query({ - query: (keyword) => { - return `everything?q=${keyword}&pageSize=10`; - }, - transformResponse: (response) => response.articles, - }), - }), -}); -export const { useGetArticlesQuery, useSearchArticlesQuery } = articlesApi; diff --git a/src/services/publishersApi.js b/src/services/publishersApi.js deleted file mode 100644 index fd074ac..0000000 --- a/src/services/publishersApi.js +++ /dev/null @@ -1,18 +0,0 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; -export const publishersApi = createApi({ - reducerPath: "publishersApi", - baseQuery: fetchBaseQuery({ - baseUrl: REACT_APP_API_URL, - headers: { - "X-Api-Key": REACT_APP_API_KEY, - }, - }), - endpoints: (builder) => ({ - getPublisher: builder.query({ - query: () => `top-headlines/sources?country=us`, - }), - }), -}); - -export const { useGetPublisherQuery } = publishersApi; diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index d0de870..0000000 --- a/src/setupTests.js +++ /dev/null @@ -1 +0,0 @@ -import "@testing-library/jest-dom"; diff --git a/src/store/index.js b/src/store/index.js deleted file mode 100644 index 50470f6..0000000 --- a/src/store/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import { configureStore } from "@reduxjs/toolkit"; -import articlesReducer from "../features/articles"; -import { publishersApi } from "../services/publishersApi"; -import { articlesApi } from "../services/articlesApi"; -const store = configureStore({ - reducer: { - articles: articlesReducer, - [publishersApi.reducerPath]: publishersApi.reducer, - [articlesApi.reducerPath]: articlesApi.reducer, - }, - middleware: (getDefaultMiddleware) => - getDefaultMiddleware().concat( - publishersApi.middleware, - articlesApi.middleware - ), -}); - -export default store; diff --git a/store/index.js b/store/index.js new file mode 100644 index 0000000..5cf4af5 --- /dev/null +++ b/store/index.js @@ -0,0 +1,15 @@ +import { configureStore } from "@reduxjs/toolkit"; +import { createWrapper } from "next-redux-wrapper"; +import articlesReducer from "../features/articles"; +import publishersReducer from "../features/publishers"; +import headlinesReducer from "../features/headlines"; +const makeStore = () => + configureStore({ + reducer: { + articles: articlesReducer, + publishers: publishersReducer, + headlines: headlinesReducer, + }, + }); + +export const wrapper = createWrapper(makeStore); diff --git a/src/index.css b/styles/globals.css similarity index 99% rename from src/index.css rename to styles/globals.css index f0c4c90..5ff951c 100644 --- a/src/index.css +++ b/styles/globals.css @@ -1,7 +1,6 @@ @tailwind base; @tailwind components; @tailwind utilities; - body { font-family: "Roboto", sans-serif; } diff --git a/tailwind.config.js b/tailwind.config.js index a3d33e0..1008fc6 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,13 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["./src/**/*.{js,jsx}"], + content: [ + "./app/**/*.{js,ts,jsx,tsx}", + "./pages/**/*.{js,ts,jsx,tsx}", + "./components/**/*.{js,ts,jsx,tsx}", + + // Or if using `src` directory: + "./src/**/*.{js,ts,jsx,tsx}", + ], theme: { extend: {}, }, diff --git a/src/utils/getDateTime.js b/utils/getDateTime.js similarity index 100% rename from src/utils/getDateTime.js rename to utils/getDateTime.js