diff --git a/.eslintrc b/.eslintrc index 0fc6dbf..3358b89 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,5 +17,8 @@ "plugin:@typescript-eslint/recommended", // Uses the recommended rules from @typescript-eslint/eslint-plugin "prettier/@typescript-eslint", // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier "plugin:prettier/recommended" // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. - ] + ], + "rules": { + "react/prop-types": "off" + } } diff --git a/package-lock.json b/package-lock.json index 7cf02bf..3033604 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2319,9 +2319,9 @@ } }, "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" }, "clean-css": { "version": "4.2.3", @@ -4304,6 +4304,16 @@ "flat-cache": "^3.0.4" } }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", diff --git a/package.json b/package.json index ec99e50..cafd0e4 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "@reduxjs/toolkit": "^1.5.0", "axios": "^0.21.1", - "classnames": "^2.2.6", + "classnames": "^2.3.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-redux": "^7.2.2", @@ -53,6 +53,7 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", + "file-loader": "^6.2.0", "html-webpack-plugin": "^5.2.0", "husky": "^4.3.8", "jest": "^26.6.3", diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg new file mode 100644 index 0000000..10cf6ca --- /dev/null +++ b/src/assets/images/logo.svg @@ -0,0 +1,22 @@ + + + + acme logo 1 + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 09fd880..1cfd8dd 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -5,7 +5,7 @@ import { fetchUserById } from "state/userProfile/actions"; import { getUsername } from "state/userProfile/selectors"; import Loader from "../Loader/Loader"; -import UserHeader from "../UserHeader/UserHeader"; +import SiteHeader from "../SiteHeader/SiteHeader"; import "styles/app.scss"; @@ -27,7 +27,7 @@ const App: FC = () => { return (
- +
); }; diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx index 478cb07..e25f612 100644 --- a/src/components/Loader/Loader.tsx +++ b/src/components/Loader/Loader.tsx @@ -1,8 +1,10 @@ import React, { FC } from "react"; const Loader: FC = () => ( -
-

Loading...

+
+
+

Loading...

+
); diff --git a/src/components/SiteHeader/SiteHeader.tsx b/src/components/SiteHeader/SiteHeader.tsx new file mode 100644 index 0000000..afc29c2 --- /dev/null +++ b/src/components/SiteHeader/SiteHeader.tsx @@ -0,0 +1,13 @@ +import React, { FC } from "react"; + +import Logo from "assets/images/logo.svg"; +import UserAvatar from "../UserAvatar/UserAvatar"; + +const SiteHeader: FC = () => ( +
+ Company name + +
+); + +export default SiteHeader; diff --git a/src/components/UserHeader/UserHeader.test.tsx b/src/components/UserAvatar/UserAvatar.test.tsx similarity index 63% rename from src/components/UserHeader/UserHeader.test.tsx rename to src/components/UserAvatar/UserAvatar.test.tsx index 3ebb33c..f6908ab 100644 --- a/src/components/UserHeader/UserHeader.test.tsx +++ b/src/components/UserAvatar/UserAvatar.test.tsx @@ -2,22 +2,22 @@ import React from "react"; import { screen } from "@testing-library/react"; import renderConnected from "utilities/test/renderConnected"; -import UserHeader from "./UserHeader"; +import UserAvatar from "./UserAvatar"; const setup = (initialState = {}) => renderConnected({ - ui: , + ui: , initialState, }); -describe("UserHeader", () => { +describe("UserAvatar", () => { it("should display username", () => { setup({ userProfile: { username: "Steve", }, }); - const userHeaderText = screen.getByText("Logged in as Steve"); - expect(userHeaderText).toBeInTheDocument(); + const userAvatarText = screen.getByText("Logged in as Steve"); + expect(userAvatarText).toBeInTheDocument(); }); }); diff --git a/src/components/UserAvatar/UserAvatar.tsx b/src/components/UserAvatar/UserAvatar.tsx new file mode 100644 index 0000000..a11617a --- /dev/null +++ b/src/components/UserAvatar/UserAvatar.tsx @@ -0,0 +1,17 @@ +import React, { FC } from "react"; +import { useSelector } from "react-redux"; +import classNames from "classnames"; + +import { getUsername } from "state/userProfile/selectors"; + +interface UserHeaderProps { + className?: string; +} + +const UserHeader: FC = ({ className }) => { + const userName = useSelector(getUsername); + const classes = classNames("user-profile", className); + return
Logged in as {userName}
; +}; + +export default UserHeader; diff --git a/src/components/UserHeader/UserHeader.tsx b/src/components/UserHeader/UserHeader.tsx deleted file mode 100644 index 960e2c7..0000000 --- a/src/components/UserHeader/UserHeader.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { FC } from "react"; -import { useSelector } from "react-redux"; - -import { getUsername } from "state/userProfile/selectors"; - -const UserHeader: FC = () => { - const userName = useSelector(getUsername); - return
Logged in as {userName}
; -}; - -export default UserHeader; diff --git a/src/types/index.d.ts b/src/types/index.d.ts new file mode 100644 index 0000000..e4d7e6d --- /dev/null +++ b/src/types/index.d.ts @@ -0,0 +1,9 @@ +declare module "*.svg" { + const content: string; + export default content; +} + +declare module "*.png" { + const content: string; + export default content; +} diff --git a/tsconfig.json b/tsconfig.json index a6a8924..87c7b53 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "allowSyntheticDefaultImports": true, "paths": { "api/*": ["./src/api/*"], + "assets/*": ["./src/assets/*"], "components/*": ["./src/components/*"], "state/*": ["./src/state/*"], "styles/*": ["./src/styles/*"], diff --git a/webpack.config.js b/webpack.config.js index 606639e..dfe584e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -33,6 +33,7 @@ module.exports = () => ({ extensions: [".ts", ".tsx", ".js", ".jsx"], alias: { api: path.resolve(sourcePath, "api/"), + assets: path.resolve(sourcePath, "assets/"), components: path.resolve(sourcePath, "components/"), state: path.resolve(sourcePath, "state/"), styles: path.resolve(sourcePath, "styles/"), @@ -69,6 +70,17 @@ module.exports = () => ({ ], exclude: /node_modules/, }, + { + test: /\.(jpe?g|png|gif|svg)$/i, + include: path.resolve(sourcePath, "assets/images"), + use: { + loader: "file-loader", + options: { + name: "[name].[ext]", + outputPath: "assets/images/", + }, + }, + }, ], },