diff --git a/.eslintrc.js b/.eslintrc.js
index 3b141c5..7ef76b0 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -22,7 +22,6 @@ module.exports = {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
- SharedArrayBuffer: 'readonly',
shallow: true,
mount: true,
expect: true,
diff --git a/__mocks__/fileMock.js b/__mocks__/fileMock.js
deleted file mode 100644
index f053ebf..0000000
--- a/__mocks__/fileMock.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = {};
diff --git a/__test__/App.spec.js b/__test__/App.spec.js
new file mode 100644
index 0000000..7282448
--- /dev/null
+++ b/__test__/App.spec.js
@@ -0,0 +1,85 @@
+import React from 'react';
+import { createStore, combineReducers } from 'redux';
+import { BrowserRouter, Switch } from 'react-router-dom';
+import { Provider } from 'react-redux';
+import auth from '@modules/auth/reducer';
+import LoginPage from '@pages/loginPage';
+import HomePage from '@pages/homePage';
+import NotFoundPage from '@pages/notFoundPage';
+import Menu from '../src/components/userMenu';
+import Footer from '../src/components/Footer/index';
+import App from '../src/routes/AppRouter';
+
+describe('Application test', () => {
+ let store;
+
+ beforeEach(() => {
+ store = createStore(
+ combineReducers({
+ auth
+ })
+ );
+ });
+ it('should render index page', () => {
+ const comp = (
+
+
+
+
+
+
+
+ );
+ const wrapper = mount(comp);
+
+ expect(wrapper.find('Home')).toBeTruthy();
+ });
+ it('should not crash app', () => {
+ const wrapper = mount( );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+ it('should work fine on Login Page', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+ it('should work fine Home Page', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+
+ it('should work fine Home Page', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+
+ it('should render without crashing', () => {
+ const wrapper = mount(
);
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ expect(wrapper.find('[href="/"]')).toHaveLength(4);
+ expect(wrapper.find('a').length).toBeGreaterThan(1);
+ expect(wrapper.find('ul')).toHaveLength(1);
+ expect(wrapper.find('li').length).toBeGreaterThan(1);
+ });
+ it('should render without crashing', () => {
+ const wrapper = shallow();
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+});
diff --git a/__test__/__mock__/localStorage.js b/__test__/__mock__/localStorage.js
new file mode 100644
index 0000000..ff8b4c5
--- /dev/null
+++ b/__test__/__mock__/localStorage.js
@@ -0,0 +1 @@
+export default {};
diff --git a/__test__/__mock__/svgrMock.js b/__test__/__mock__/svgrMock.js
new file mode 100644
index 0000000..1b3addc
--- /dev/null
+++ b/__test__/__mock__/svgrMock.js
@@ -0,0 +1 @@
+module.exports = 'icon-mock';
diff --git a/__test__/__snapshots__/App.spec.js.snap b/__test__/__snapshots__/App.spec.js.snap
new file mode 100644
index 0000000..0573170
--- /dev/null
+++ b/__test__/__snapshots__/App.spec.js.snap
@@ -0,0 +1,979 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Application test should not crash app 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Welcome to ErrorSwag, what on your mind?
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Application test should render without crashing 1`] = `
+
+
+
+`;
+
+exports[`Application test should render without crashing 2`] = `
+
+`;
+
+exports[`Application test should work fine Home Page 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ Welcome to ErrorSwag, what on your mind?
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Application test should work fine Home Page 2`] = `
+
+
+
+
+
+
+ THE PAGE YOU ARE LOOKING FOR MIGHT HAVE BEEN REMOVED HAD ITS NAME CHANGED OR ITS TEMPORARILY UNAVAILABLE
+
+
+
+ GO HOME
+
+
+
+
+
+
+`;
+
+exports[`Application test should work fine on Login Page 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home
+
+
+
+
+
+
+
+
+
+`;
diff --git a/__test__/__snapshots__/store.spec.js.snap b/__test__/__snapshots__/store.spec.js.snap
new file mode 100644
index 0000000..93fcafd
--- /dev/null
+++ b/__test__/__snapshots__/store.spec.js.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Test REDUX STORE test redux store 1`] = `
+Object {
+ "dispatch": [Function],
+ "getState": [Function],
+ "replaceReducer": [Function],
+ "subscribe": [Function],
+ Symbol(observable): [Function],
+}
+`;
diff --git a/__test__/components/navbar.spec.js b/__test__/components/navbar.spec.js
new file mode 100644
index 0000000..2f06930
--- /dev/null
+++ b/__test__/components/navbar.spec.js
@@ -0,0 +1,81 @@
+import React from 'react';
+import { BrowserRouter as Router } from 'react-router-dom';
+import NavBar, { AuthButtons } from '@components/NavBar';
+
+const mockState = menuOpen => {
+ const setState = jest.fn();
+ const useStateSpy = jest.spyOn(React, 'useState');
+ useStateSpy.mockImplementation(() => [true, setState]);
+};
+
+describe(' ', () => {
+ let wrapper;
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should test when user is not logged in and menu is clicked', () => {
+ mockState(false);
+ wrapper = mount(
+
+
+
+ );
+ wrapper.find('#hamburger').simulate('click');
+ mockState(true);
+ expect(wrapper.find('#hamburger').hasClass('active')).toEqual(true);
+ });
+
+ it('should test when user is logged in', () => {
+ wrapper = mount(
+
+
+
+ );
+ expect(
+ wrapper
+ .find('#menu')
+ .childAt(0)
+ .hasClass('avatar')
+ ).toEqual(true);
+ });
+
+ it('should display auth button when user is not logged in ', () => {
+ wrapper = mount(
+
+
+
+ );
+ expect(
+ wrapper
+ .setProps({
+ children:
+ })
+ .find('#auth-buttons')
+ .children()
+ ).toHaveLength(2);
+
+ expect(
+ toJson(
+ wrapper
+ .setProps({
+ children:
+ })
+ .find('#auth-buttons')
+ .childAt(0)
+ ).props.title
+ ).toEqual('Login');
+
+ expect(
+ toJson(
+ wrapper
+ .setProps({
+ children:
+ })
+ .find('#auth-buttons')
+ .childAt(1)
+ ).props.title
+ ).toEqual('Signup');
+ });
+});
diff --git a/__test__/reducers/auth.spec.js b/__test__/reducers/auth.spec.js
new file mode 100644
index 0000000..368eae4
--- /dev/null
+++ b/__test__/reducers/auth.spec.js
@@ -0,0 +1,26 @@
+import auth from '@modules/auth/reducer';
+
+describe('Test auth reducer function', () => {
+ const initialState = {
+ isLoginPending: true,
+ isAuthenticated: false,
+ user: {}
+ };
+ it('should return the initial state', () => {
+ expect(auth(initialState, {})).toEqual(initialState);
+ });
+
+ it('should handle successful login', () => {
+ const successAction = {
+ type: 'LOGIN_SUCCESS',
+ user: {
+ username: 'timi'
+ }
+ };
+ expect(auth(initialState, successAction)).toEqual({
+ isLoginPending: false,
+ isAuthenticated: !successAction.user,
+ user: successAction.user
+ });
+ });
+});
diff --git a/__test__/setup.js b/__test__/setup.js
new file mode 100644
index 0000000..bc09e99
--- /dev/null
+++ b/__test__/setup.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import { configure, shallow, mount, render } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import toJson from 'enzyme-to-json';
+import moxios from 'moxios';
+import thunk from 'redux-thunk';
+import configureMockStore from 'redux-mock-store';
+import localStorage from './__mock__/localStorage';
+
+const middleware = [thunk];
+const mockStore = configureMockStore(middleware);
+
+global.React = React;
+global.shallow = shallow;
+global.render = render;
+global.mount = mount;
+global.toJson = toJson;
+global.moxios = moxios;
+global.mockStore = mockStore;
+global.localStorage = localStorage;
+
+configure({ adapter: new Adapter() });
diff --git a/__test__/store.spec.js b/__test__/store.spec.js
new file mode 100644
index 0000000..48f65ef
--- /dev/null
+++ b/__test__/store.spec.js
@@ -0,0 +1,7 @@
+import store from '../src/store/index';
+
+describe('Test REDUX STORE', () => {
+ it('test redux store', () => {
+ expect(store).toMatchSnapshot();
+ });
+});
diff --git a/jest.config.js b/jest.config.js
index 478e2dc..1eaa191 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,47 +1,32 @@
module.exports = {
+ setupFiles: ['/__test__/setup.js'],
coverageDirectory: 'coverage',
- testPathIgnorePatterns: ['/node_modules/'],
- transformIgnorePatterns: ['/node_modules/'],
+ transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'],
moduleNameMapper: {
- '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css)$':
- '/__mocks__/fileMock.js',
- '\\.(css|less)$': '/__mocks__/styleMock.js',
+ '.+\\.(css|scss)$': 'identity-obj-proxy',
+ '\\.svg': '/__test__/__mock__/svgrMock.js',
+ '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2)$':
+ 'jest-transform-stub',
'^@config(.*)$': '/src/config$1',
'^@components(.*)$': '/src/components$1',
- '^@containers(.*)$': '/src/containers$1',
- '^@actions(.*)$': '/src/actions$1',
+ '^@modules(.*)$': '/src/store/modules$1',
'^@pages(.*)$': '/src/pages$1',
+ '^@assets(.*)$': '/src/assets$1',
'@/(.*)$': '/src$1'
},
collectCoverageFrom: [
- '**/*.{js,jsx}',
- '!**/node_modules/**',
- '!jest.config.js',
- '!**/dist/**',
- '!**/webpack-build-utils/**',
- '!README.md',
- 'Procfile',
- 'Postcss.config.js',
- '!package.json',
- '!package-lock.json',
- '!cypress.json',
- '!/server.js',
- '!webpack.common.js',
- '!webpack.config.js',
- '!**/coverage/**',
- '!**/tests/**',
- '!src/actions/**',
- '!src/assets/**',
- '!src/reducers/**',
- '!src/store/**',
- '!src/index.js',
- '!src/config/**',
- '!src/containers/**',
- '!index.js',
- '!src/pages/home.js',
- '!postcss.config.js',
- '!src/utils/**',
- '!**/cypress/**',
- '!**/*.css'
- ]
+ 'src/**/*.{js,jsx}',
+ '!/__test__/**/*.(spec|test).{js,jsx}'
+ ],
+ coveragePathIgnorePatterns: [
+ '/node_modules',
+ '/dist/',
+ '/src/utils',
+ '/src/components/icons',
+ '/src/index.js'
+ ],
+ testPathIgnorePatterns: ['/node_modules/'],
+ transform: {
+ '^.+\\.(js|jsx|mjs)$': '/node_modules/babel-jest'
+ }
};
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000..8687268
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "es2017",
+ "allowSyntheticDefaultImports": false,
+ "baseUrl": "./",
+ "paths": {
+ "@config/*": ["src/config/*"],
+ "@components/*": ["src/components/*"],
+ "@modules/*": ["src/store/modules/*"],
+ "@pages/*": ["src/pages/*"],
+ "@assets/*": ["src/assets/*"]
+ }
+ },
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/package.json b/package.json
index 968b185..40d0e69 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,8 @@
},
"husky": {
"hooks": {
- "pre-commit": "lint-staged"
+ "pre-commit": "lint-staged",
+ "pre-push": "npm test"
}
},
"lint-staged": {
@@ -47,6 +48,8 @@
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
+ "@svgr/webpack": "^4.3.2",
+ "@testing-library/react-hooks": "^1.1.0",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-module-resolver": "^3.2.0",
@@ -54,7 +57,7 @@
"cypress": "^3.4.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
- "enzyme-to-json": "^3.3.5",
+ "enzyme-to-json": "^3.4.0",
"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.1",
"eslint-config-prettier": "^6.0.0",
@@ -64,27 +67,36 @@
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.14.3",
+ "extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^4.1.0",
"husky": "^3.0.2",
+ "identity-obj-proxy": "^3.0.0",
"jest": "^24.8.0",
+ "jest-transform-stub": "^2.0.0",
"lint-staged": "^9.2.1",
+ "moxios": "^0.4.0",
+ "node-sass": "^4.12.0",
"postcss-loader": "^3.0.0",
"prettier": "^1.18.2",
"prettier-eslint": "^9.0.0",
"prettier-eslint-cli": "^5.0.0",
"pretty-quick": "^1.11.1",
"purgecss-webpack-plugin": "^1.5.0",
+ "redux-mock-store": "^1.5.3",
+ "sass-loader": "^7.1.0",
+ "webpack": "^4.39.1",
"webpack-dev-server": "^3.7.2"
},
"dependencies": {
"autoprefixer": "^9.6.1",
+ "axios": "^0.19.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.1.0",
"express": "^4.17.1",
"glob": "^7.1.4",
"html-webpack-plugin": "^3.2.0",
+ "jest-svg-transformer": "^1.0.0",
"mini-css-extract-plugin": "^0.8.0",
- "node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"prop-types": "^15.7.2",
"react": "^16.8.6",
@@ -92,15 +104,15 @@
"react-hot-loader": "^4.12.10",
"react-redux": "^7.1.0",
"react-router-dom": "^5.0.1",
+ "react-scripts": "^3.0.1",
+ "react-transition-group": "^4.2.1",
"redux": "^4.0.4",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
- "sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"tailwindcss": "^1.0.6",
"terser-webpack-plugin": "^1.3.0",
"react-svg-loader": "^3.0.3",
- "@svgr/webpack": "^4.3.2",
"webpack": "^4.38.0",
"webpack-cli": "^3.3.6",
"webpack-merge": "^4.2.1"
diff --git a/postcss.config.js b/postcss.config.js
index 52a8bf0..06a4700 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,3 +1,4 @@
+/* eslint-disable global-require */
module.exports = {
plugins: [require('tailwindcss'), require('autoprefixer')]
};
diff --git a/public/images/arrow_down.svg b/public/images/arrow_down.svg
new file mode 100644
index 0000000..b455472
--- /dev/null
+++ b/public/images/arrow_down.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/public/images/logo.svg b/public/images/logo.svg
new file mode 100644
index 0000000..ea2e101
--- /dev/null
+++ b/public/images/logo.svg
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/styles/_colors.scss b/public/styles/_colors.scss
new file mode 100644
index 0000000..392ad1d
--- /dev/null
+++ b/public/styles/_colors.scss
@@ -0,0 +1,10 @@
+$primary: #3dbfb7;
+$danger: #fc4949;
+$black: #313131;
+$white: #ffffff;
+$dark-grey: #535353;
+$light-grey: #f5f5f5;
+$yellow: #535353;
+$round-button-color: rgba(196, 196, 196, 0.16);
+$page-bg-color: #f7fcfc;
+$black-transparent: rgba(54, 54, 54, 0.45);
diff --git a/src/.DS_Store b/src/.DS_Store
index 3bc8cf7..6737008 100644
Binary files a/src/.DS_Store and b/src/.DS_Store differ
diff --git a/src/assets/icons/avatar.svg b/src/assets/icons/avatar.svg
new file mode 100644
index 0000000..1a6eb2b
--- /dev/null
+++ b/src/assets/icons/avatar.svg
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/icons/clear.svg b/src/assets/icons/clear.svg
new file mode 100644
index 0000000..63797e6
--- /dev/null
+++ b/src/assets/icons/clear.svg
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/src/assets/icons/facebook.js b/src/assets/icons/facebook.svg
similarity index 64%
rename from src/assets/icons/facebook.js
rename to src/assets/icons/facebook.svg
index bb98cb2..c0e4825 100644
--- a/src/assets/icons/facebook.js
+++ b/src/assets/icons/facebook.svg
@@ -1,14 +1,8 @@
-import React from 'react';
-
-const facebook = () => (
-);
-
-export default facebook;
diff --git a/src/assets/icons/index.js b/src/assets/icons/index.js
index 7ad7fa8..1376c78 100644
--- a/src/assets/icons/index.js
+++ b/src/assets/icons/index.js
@@ -1,7 +1,21 @@
-// import YoutubeIcon from './youtube.svg';
-// import FacebookIcon from './facebook.svg';
-// import LinkedInIcon from './linkedin.svg';
-// import InstagramIcon from './instagram.svg';
-// import TwitterIcon from './twitter.svg';
+import ClearIcon from './clear.svg';
+import SearchIcon from './search.svg';
+import NotificationIcon from './notification.svg';
+import AvatarIcon from './avatar.svg';
+import FacebookIcon from './facebook.svg';
+import InstagramIcon from './instagram.svg';
+import LinkedInIcon from './linkedin.svg';
+import YoutubeIcon from './youtube.svg';
+import TwitterIcon from './twitter.svg';
-// export { YoutubeIcon, FacebookIcon, LinkedInIcon, InstagramIcon, TwitterIcon };
+export {
+ SearchIcon,
+ NotificationIcon,
+ ClearIcon,
+ AvatarIcon,
+ FacebookIcon,
+ InstagramIcon,
+ LinkedInIcon,
+ YoutubeIcon,
+ TwitterIcon
+};
diff --git a/src/assets/icons/instagram.js b/src/assets/icons/instagram.js
deleted file mode 100644
index 90debe7..0000000
--- a/src/assets/icons/instagram.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-
-const instagram = () => (
-
-
-
-);
-
-export default instagram;
diff --git a/src/assets/icons/instagram.svg b/src/assets/icons/instagram.svg
new file mode 100644
index 0000000..bffd2b8
--- /dev/null
+++ b/src/assets/icons/instagram.svg
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/assets/icons/linkedin.js b/src/assets/icons/linkedin.js
deleted file mode 100644
index 36612af..0000000
--- a/src/assets/icons/linkedin.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-
-const linkedin = () => (
-
-
-
-);
-
-export default linkedin;
diff --git a/src/assets/icons/linkedin.svg b/src/assets/icons/linkedin.svg
new file mode 100644
index 0000000..3e5261c
--- /dev/null
+++ b/src/assets/icons/linkedin.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/assets/icons/notification.svg b/src/assets/icons/notification.svg
new file mode 100644
index 0000000..cd93a10
--- /dev/null
+++ b/src/assets/icons/notification.svg
@@ -0,0 +1,15 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/icons/search.svg b/src/assets/icons/search.svg
new file mode 100644
index 0000000..a8ebd03
--- /dev/null
+++ b/src/assets/icons/search.svg
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/src/assets/icons/twitter.js b/src/assets/icons/twitter.svg
similarity index 83%
rename from src/assets/icons/twitter.js
rename to src/assets/icons/twitter.svg
index 9ef379f..2f9698a 100644
--- a/src/assets/icons/twitter.js
+++ b/src/assets/icons/twitter.svg
@@ -1,14 +1,8 @@
-import React from 'react';
-
-const twitter = () => (
-
-);
-
-export default twitter;
+
\ No newline at end of file
diff --git a/src/assets/icons/youtube.js b/src/assets/icons/youtube.js
deleted file mode 100644
index 8e10392..0000000
--- a/src/assets/icons/youtube.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-
-const youtube = () => (
-
-
-
-);
-
-export default youtube;
diff --git a/src/assets/icons/youtube.svg b/src/assets/icons/youtube.svg
new file mode 100644
index 0000000..c309f46
--- /dev/null
+++ b/src/assets/icons/youtube.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png
index 70b6355..e774491 100644
Binary files a/src/assets/images/logo.png and b/src/assets/images/logo.png differ
diff --git a/src/assets/images/notfound.png b/src/assets/images/notfound.png
new file mode 100644
index 0000000..53ee947
Binary files /dev/null and b/src/assets/images/notfound.png differ
diff --git a/src/components/App.js b/src/components/App.js
deleted file mode 100644
index 108c6d0..0000000
--- a/src/components/App.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { BrowserRouter as Router } from 'react-router-dom';
-import Routes from '../routes/AppRouter';
-import Footer from './Footer/Footer';
-
-const App = () => {
- return (
-
-
-
-
- );
-};
-
-export default App;
diff --git a/src/components/Footer/Footer.css b/src/components/Footer/Footer.css
deleted file mode 100644
index 514b983..0000000
--- a/src/components/Footer/Footer.css
+++ /dev/null
@@ -1,9 +0,0 @@
-@import url('https://fonts.googleapis.com/css?family=Poppins:400,500,600,700,800,900|Roboto&display=swap');
-
-
- .footer {
- font-family: 'Poppins', sans-serif;
- position: fixed;
- left: 0px;
- bottom: 0px;
- }
diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js
deleted file mode 100644
index 49b853c..0000000
--- a/src/components/Footer/Footer.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import './Footer.css';
-import YoutubeIcon from '../../assets/icons/youtube';
-import FacebookIcon from '../../assets/icons/facebook';
-import LinkedInIcon from '../../assets/icons/linkedin';
-import InstagramIcon from '../../assets/icons/instagram';
-import TwitterIcon from '../../assets/icons/twitter';
-
-const Footer = () => {
- return (
-
-
-
Designed by Kifaru Team
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Footer;
diff --git a/src/components/Footer/Footer.scss b/src/components/Footer/Footer.scss
new file mode 100644
index 0000000..44ef8e2
--- /dev/null
+++ b/src/components/Footer/Footer.scss
@@ -0,0 +1,11 @@
+@import url('https://fonts.googleapis.com/css?family=Poppins:400,500,600,700,800,900|Roboto&display=swap');
+@import '../../../public/styles/colors.scss';
+
+.footer {
+ font-family: 'Poppins', sans-serif;
+ position: fixed;
+ left: 0px;
+ bottom: 0px;
+ border-top: 1px solid $light-grey;
+ @apply text-danger text-base font-bold py-10;
+}
diff --git a/src/components/Footer/index.js b/src/components/Footer/index.js
new file mode 100644
index 0000000..2429032
--- /dev/null
+++ b/src/components/Footer/index.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import './Footer.scss';
+import {
+ YoutubeIcon,
+ FacebookIcon,
+ LinkedInIcon,
+ InstagramIcon,
+ TwitterIcon
+} from '../../assets/icons';
+
+const Footer = () => (
+
+
+
Designed by Kifaru Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+export default Footer;
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
new file mode 100644
index 0000000..1057d6f
--- /dev/null
+++ b/src/components/Layout.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import NavBar from '@components/NavBar';
+import Footer from '@components/Footer';
+
+const Layout = ({ children }) => (
+ <>
+
+ {children}
+
+ >
+);
+
+Layout.propTypes = {
+ children: PropTypes.node.isRequired
+};
+
+export default Layout;
diff --git a/src/components/NavBar/NavBar.scss b/src/components/NavBar/NavBar.scss
new file mode 100644
index 0000000..dbf01d8
--- /dev/null
+++ b/src/components/NavBar/NavBar.scss
@@ -0,0 +1,90 @@
+@import '../../../public/styles/colors.scss';
+
+.logo {
+ width: 163px;
+ height: 55px;
+}
+
+.avatar {
+ &:after {
+ content: url('../../../public/images/arrow_down.svg');
+ margin-left: 1rem;
+ }
+}
+
+.btn {
+ @screen sm {
+ @apply mx-3;
+ }
+ @screen md {
+ @apply mx-5;
+ }
+ @apply flex justify-center items-center;
+}
+
+.btn:focus {
+ @apply outline-none;
+}
+
+.small-button {
+ @extend .btn;
+ width: 35px;
+}
+
+.hamburger span {
+ cursor: pointer;
+ border-radius: 1px;
+ height: 3px;
+ width: 20px;
+ background: $black;
+ position: absolute;
+ display: block;
+ content: '';
+ &:before,
+ &:after {
+ cursor: pointer;
+ border-radius: 1px;
+ height: 3px;
+ background: black;
+ position: absolute;
+ display: block;
+ content: '';
+ }
+ &:before {
+ top: -8px;
+ width: 28px;
+ }
+ &:after {
+ bottom: -8px;
+ width: 13px;
+ }
+}
+
+.hamburger {
+ span {
+ transition: all 500ms ease-in-out;
+ &:before,
+ &:after {
+ transition: all 500ms ease-in-out;
+ }
+ }
+ &.active span {
+ background-color: transparent;
+ &:before,
+ &:after {
+ top: 0;
+ }
+ &:before {
+ transform: rotate(45deg);
+ }
+ &:after {
+ transform: rotate(-45deg);
+ width: 28px;
+ }
+ }
+}
+
+.wrapper {
+ background-color: $white;
+ box-shadow: 0 2px 2px -2px #c4c4c490;
+}
diff --git a/src/components/NavBar/index.js b/src/components/NavBar/index.js
new file mode 100644
index 0000000..a222db5
--- /dev/null
+++ b/src/components/NavBar/index.js
@@ -0,0 +1,116 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Link } from 'react-router-dom';
+import { NotificationIcon, AvatarIcon, SearchIcon } from '../../assets/icons';
+import './NavBar.scss';
+import logo from '../../assets/images/logo.png';
+
+const NavBar = ({ isLoggedIn, user }) => {
+ const [menuOpen, setMenuOpen] = React.useState(false);
+
+ const toggleMenu = () => {
+ setMenuOpen(!menuOpen);
+ };
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+NavBar.defaultProps = {
+ isLoggedIn: false,
+ user: {}
+};
+
+NavBar.propTypes = {
+ isLoggedIn: PropTypes.bool,
+ user: PropTypes.objectOf(PropTypes.string)
+};
+
+const MenuIcon = ({ isLoggedIn, toggleMenu, menuOpen }) => {
+ return isLoggedIn ? (
+
+
+
+ ) : (
+
+
+
+ );
+};
+
+MenuIcon.propTypes = {
+ isLoggedIn: PropTypes.bool.isRequired,
+ menuOpen: PropTypes.bool.isRequired,
+ toggleMenu: PropTypes.func.isRequired
+};
+
+export const AuthButtons = ({ show }) => {
+ return show ? (
+ <>
+
+ LOGIN
+
+
+
+ GET STARTED
+
+ >
+ ) : null;
+};
+
+AuthButtons.propTypes = {
+ show: PropTypes.bool.isRequired
+};
+
+export default NavBar;
diff --git a/src/containers/Footer.jsx b/src/containers/Footer.jsx
deleted file mode 100644
index e69de29..0000000
diff --git a/src/containers/Layout.jsx b/src/containers/Layout.jsx
deleted file mode 100644
index e69de29..0000000
diff --git a/src/containers/Nav.jsx b/src/containers/Nav.jsx
deleted file mode 100644
index e69de29..0000000
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index 7f39374..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,5 +0,0 @@
-@tailwind base;
-
-@tailwind components;
-
-@tailwind utilities;
diff --git a/src/index.js b/src/index.js
index ad80a86..18f2efc 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,8 +1,15 @@
import React from 'react';
import { render } from 'react-dom';
-import App from './components/App';
-import './index.css';
+import { Provider } from 'react-redux';
+import App from './routes/AppRouter';
+import store from './store';
+import './main.scss';
const app = document.querySelector('#app');
-render( , app);
+render(
+
+
+ ,
+ app
+);
diff --git a/src/main.scss b/src/main.scss
new file mode 100644
index 0000000..2cbdc93
--- /dev/null
+++ b/src/main.scss
@@ -0,0 +1,38 @@
+@tailwind base;
+
+@tailwind components;
+
+@tailwind utilities;
+
+@import '../public/styles/colors.scss';
+@import url('https://fonts.googleapis.com/css?family=Poppins:400,500,600,700,800,900|Roboto&display=swap');
+
+:root {
+ --font: 'Poppins', sans-serif;
+ font-family: var(--font);
+ font-style: normal;
+}
+
+body {
+ padding: 0;
+ margin: 0;
+ background-color: $page-bg-color;
+ font-weight: 400;
+}
+
+.btn-medium {
+ font-size: 0.85rem;
+ font-weight: 600;
+}
+
+.red-button {
+ @extend .btn-medium;
+ border: 2px solid $danger;
+ color: $danger;
+ border-radius: 5px;
+ box-sizing: border-box;
+}
+
+.article-body {
+ --font: Roboto;
+}
diff --git a/src/pages/home.js b/src/pages/home.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/pages/homePage.js b/src/pages/homePage.js
new file mode 100644
index 0000000..79420b6
--- /dev/null
+++ b/src/pages/homePage.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import Layout from '@components/Layout';
+import logo from '../assets/images/logo.png';
+
+const Homepage = () => {
+ return (
+
+
+
+ Welcome to ErrorSwag, what on your mind?
+
+
+
+
+ Login
+
+
+
+
+ );
+};
+
+export default Homepage;
diff --git a/src/pages/hompage.js b/src/pages/hompage.js
deleted file mode 100644
index fed2f04..0000000
--- a/src/pages/hompage.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
-import logo from '../assets/images/logo.png';
-import Footer from '../components/Footer/Footer';
-import Menu from '../components/userMenu';
-
-const Homepage = () => {
- return (
-
-
- Welcome to ErrorSwag, what on your mind?
-
-
-
-
- Login
-
-
-
-
-
- );
-};
-
-export default Homepage;
diff --git a/src/pages/loginPage.js b/src/pages/loginPage.js
index e69de29..467ecd5 100644
--- a/src/pages/loginPage.js
+++ b/src/pages/loginPage.js
@@ -0,0 +1,46 @@
+import React, { Component } from 'react';
+import { Link } from 'react-router-dom';
+import Layout from '@components/Layout';
+
+class LoginPage extends Component {
+ style = {
+ backgroundColor: 'sky-blue',
+ color: 'black',
+ padding: '7px 9px',
+ marginLeft: '80%',
+ border: 'none'
+ };
+ input = {
+ width: '100%',
+ border: '1px solid #333',
+ height: '2em'
+ };
+ label = {
+ width: '50%',
+ height: '2em'
+ };
+ render() {
+ return (
+
+
+
+ Home
+
+
+
+
+ );
+ }
+}
+
+export default LoginPage;
diff --git a/src/pages/notFoundPage.js b/src/pages/notFoundPage.js
new file mode 100644
index 0000000..fc32241
--- /dev/null
+++ b/src/pages/notFoundPage.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import logo from '../assets/images/notfound.png';
+
+const NotFoundPage = () => (
+
+
+
+ THE PAGE YOU ARE LOOKING FOR MIGHT HAVE BEEN REMOVED HAD ITS NAME CHANGED
+ OR ITS TEMPORARILY UNAVAILABLE
+
+
+ GO HOME
+
+
+);
+
+export default NotFoundPage;
diff --git a/src/reducers/index.js b/src/reducers/index.js
deleted file mode 100644
index f62860a..0000000
--- a/src/reducers/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { combineReducers } from 'redux';
-import auth from '@reducers/auth';
-
-export default combineReducers({
- auth
-});
diff --git a/src/routes/AppRouter.js b/src/routes/AppRouter.js
index bc52f14..682c9ce 100644
--- a/src/routes/AppRouter.js
+++ b/src/routes/AppRouter.js
@@ -1,11 +1,17 @@
import React from 'react';
-import { Route, Switch } from 'react-router-dom';
-import Homepage from '../pages/hompage';
+import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
+import LandingPage from '@pages/loginPage';
+import HomePage from '@pages/homePage';
+import NotFoundPage from '@pages/notFoundPage';
-const Routes = () => (
-
-
-
+const App = () => (
+
+
+
+
+
+
+
);
-export default Routes;
+export default App;
diff --git a/src/store/index.js b/src/store/index.js
index b86ab76..8d09dbd 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,16 +1,14 @@
-import { createStore, applyMiddleware, compose } from 'redux';
+import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunkMiddleware from 'redux-thunk';
-import { createLogger } from 'redux-logger';
-import rootReducer from '@reducers';
+import auth from '@modules/auth/reducer';
+
+const rootReducer = combineReducers({
+ auth
+});
-const loggerMiddleware = createLogger();
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const middlewares = [thunkMiddleware];
-if (process.env.NODE_ENV === 'development') {
- middlewares.push(loggerMiddleware);
-}
-
const store = createStore(
rootReducer,
{},
diff --git a/src/actions/auth/actionTypes.js b/src/store/modules/auth/actionTypes.js
similarity index 100%
rename from src/actions/auth/actionTypes.js
rename to src/store/modules/auth/actionTypes.js
diff --git a/src/actions/auth/index.js b/src/store/modules/auth/actions.js
similarity index 100%
rename from src/actions/auth/index.js
rename to src/store/modules/auth/actions.js
diff --git a/src/reducers/auth.js b/src/store/modules/auth/reducer.js
similarity index 88%
rename from src/reducers/auth.js
rename to src/store/modules/auth/reducer.js
index 99708c3..8d22353 100644
--- a/src/reducers/auth.js
+++ b/src/store/modules/auth/reducer.js
@@ -1,4 +1,4 @@
-import actionTypes from '@actions/auth/actionTypes';
+import actionTypes from '@modules/auth/actionTypes';
const { LOGIN_SUCCESS } = actionTypes;
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..172e31b
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,24 @@
+module.exports = {
+ theme: {
+ screens: {
+ sm: { min: '360px' },
+ md: { min: '768px' },
+ lg: { min: '992px' },
+ xl: { min: '1200px' }
+ },
+ textColor: {
+ primary: '#3dbfb7',
+ secondary: '#313131',
+ danger: '#fc4949',
+ white: '#ffffff'
+ },
+ backgroundColor: theme => ({
+ ...theme('colors'),
+ primary: '#3dbfb7',
+ secondary: '#313131',
+ danger: '#fc4949'
+ })
+ },
+ variants: {},
+ plugins: []
+};
diff --git a/tests/App.spec.js b/tests/App.spec.js
deleted file mode 100644
index 8872e0a..0000000
--- a/tests/App.spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import toJson from 'enzyme-to-json';
-import App from '../src/components/App';
-import { shallow, mount } from './enzyme';
-import HomePage from '../src/pages/hompage';
-import Routes from '../src/routes/AppRouter';
-import Menu from '../src/components/userMenu';
-import Footer from '../src/components/Footer/Footer';
-
-describe('Application test', () => {
- it('should work fine on App', () => {
- const wrapper = shallow( );
-
- expect(toJson(wrapper)).toMatchSnapshot();
- });
- it('should work fine Home Page', () => {
- const wrapper = shallow( );
-
- expect(toJson(wrapper)).toMatchSnapshot();
- });
- it('should work fine on Routes', () => {
- const wrapper = shallow( );
-
- expect(toJson(wrapper)).toMatchSnapshot();
- });
- it('should render without crashing', () => {
- const wrapper = mount( );
-
- expect(toJson(wrapper)).toMatchSnapshot();
- expect(wrapper.find('[href="/"]')).toHaveLength(4);
- expect(wrapper.find('a').length).toBeGreaterThan(1);
- expect(wrapper.find('ul')).toHaveLength(1);
- expect(wrapper.find('li').length).toBeGreaterThan(1);
- });
- it('should render without crashing', () => {
- const wrapper = shallow();
-
- expect(toJson(wrapper)).toMatchSnapshot();
- });
-});
diff --git a/tests/__snapshots__/App.spec.js.snap b/tests/__snapshots__/App.spec.js.snap
deleted file mode 100644
index eb0f7e4..0000000
--- a/tests/__snapshots__/App.spec.js.snap
+++ /dev/null
@@ -1,152 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Application test should render without crashing 1`] = `
-
-
-
-`;
-
-exports[`Application test should render without crashing 2`] = `
-
-`;
-
-exports[`Application test should work fine Home Page 1`] = `
-
-
- Welcome to ErrorSwag, what on your mind?
-
-
-
-
- Login
-
-
-
-
-
-`;
-
-exports[`Application test should work fine on App 1`] = `
-
-
-
-
-`;
-
-exports[`Application test should work fine on Routes 1`] = `
-
-
-
-`;
diff --git a/tests/enzyme.js b/tests/enzyme.js
deleted file mode 100644
index 830ed1d..0000000
--- a/tests/enzyme.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import Enzyme, { configure, shallow, mount, render } from 'enzyme';
-import Adapter from 'enzyme-adapter-react-16';
-
-configure({ adapter: new Adapter() });
-
-export { shallow, mount, render };
-
-export default Enzyme;
diff --git a/webpack.common.js b/webpack.common.js
index e24951f..75c8e25 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -9,12 +9,10 @@ module.exports = {
alias: {
'@components': path.resolve(__dirname, 'src/components'),
'@containers': path.resolve(__dirname, 'src/containers'),
- '@reducers': path.resolve(__dirname, 'src/reducers'),
- '@actions': path.resolve(__dirname, 'src/actions'),
+ '@modules': path.resolve(__dirname, 'src/store/modules'),
'@pages': path.resolve(__dirname, 'src/pages'),
- '@config': path.resolve(__dirname, 'src/'),
- '@fonts': path.resolve(__dirname, 'public/assets/fonts'),
- '@images': path.resolve(__dirname, 'public/assets/images'),
+ '@config': path.resolve(__dirname, 'src/config'),
+ '@assets': path.resolve(__dirname, 'src/assets'),
'@utils': path.resolve(__dirname, 'src/utils')
}
},
@@ -27,6 +25,16 @@ module.exports = {
loader: 'babel-loader'
}
},
+ {
+ test: /\.(png|jpeg|jpg)$/,
+ use: {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[hash].[ext]',
+ outputPath: 'imgs'
+ }
+ }
+ },
{
test: /\.svg$/,
use: [
@@ -42,16 +50,6 @@ module.exports = {
}
]
},
- {
- test: /\.(png|jpeg|jpg)$/,
- use: {
- loader: 'file-loader',
- options: {
- name: '[name].[hash].[ext]',
- outputPath: 'imgs'
- }
- }
- },
{
test: /\.(css|scss|sass)/i,
use: [