Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,420 changes: 5,617 additions & 8,803 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@
"main": "index.js",
"scripts": {
"serve": "webpack serve --mode development",
"build": "webpack --mode production"
"build": "webpack --mode production",
"test": "jest",
"test:watch": "jest --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@devexpress/dx-react-chart": "^2.7.6",
"@devexpress/dx-react-chart-material-ui": "^2.7.6",
"@devexpress/dx-react-core": "^2.7.6",
"@emotion/react": "^11.6.0",
"@emotion/styled": "^11.6.0",
"@material-ui/core": "^4.12.3",
"@mui/icons-material": "^5.1.1",
"@mui/material": "^5.1.1",
"@mui/styles": "^5.2.0",
"date-fns": "^2.27.0",
"material-ui-chip-input": "^2.0.0-beta.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.6",
Expand All @@ -27,10 +35,16 @@
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-react": "^7.16.0",
"@testing-library/react": "^12.1.2",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.5",
"babel-jest": "^27.4.2",
"babel-loader": "^8.2.3",
"css-loader": "^6.5.1",
"enzyme": "^3.11.0",
"enzyme-to-json": "^3.6.2",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"jest": "^27.4.3",
"style-loader": "^3.3.1",
"webpack": "^5.64.0",
"webpack-cli": "^4.9.1",
Expand Down
6 changes: 6 additions & 0 deletions src/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
6 changes: 4 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Route, Routes, Outlet } from 'react-router';
import { BrowserRouter, Link } from "react-router-dom";
import NavigationBar from "Components/NavigationBar";
import TasksListPage from "./pages/TaskListPage";
import MyTasksListPage from "./pages/MyTasksListPage";
import DashboardPage from "./pages/DashboardPage";
import './styles.css';
import { Provider } from "react-redux";

Expand All @@ -20,9 +22,9 @@ function App () {
{/* /tasks */}
<Route path="tasks" element={<TasksListPage />} />
{/* /tasks/self */}
<Route path="tasks/self" element={<div>My Tasks</div>} />
<Route path="tasks/self" element={<MyTasksListPage />} />
{/* /dashboard */}
<Route path="dashboard" element={<div>Dashboard in construction</div>} />
<Route path="dashboard" element={<DashboardPage />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
63 changes: 63 additions & 0 deletions src/actions/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// action types
// event actions
export const API_START = 'API_START';
export const API_POST = 'API_POST';
export const API_PUT = 'API_PUT';
export const API_DASHBOARD = 'API_DASHBOARD';
export const API_SUCCESS = 'API_SUCCESS';
export const POST_SUCCESS = 'POST_SUCCESS';
export const DASHBOARD_SUCCESS = 'DASHBOARD_SUCCESS';
export const API_FAILURE = 'API_FAILURE';
export const API_SELF_START = 'API_SELF_START';


export const apiStart = ({body, method, url}) => ({
type: API_START,
payload: body,
meta: {method, url, body}
});

export const apiSelfStart = ({body, method, url}) => ({

type: API_SELF_START,
payload: body,
meta: {body, method, url}
});

export const apiPost = ({body, method='POST', url}) => ({

type: API_POST,
payload: body,
meta: {body, method, url}
});

export const apiPut = ({body, method='POST', url}) => ({
type: API_PUT,
payload: body,
meta: {body, method, url}
});

export const dashboardStart = ({body, method, url}) => ({
type: API_DASHBOARD,
payload: body,
meta: {body, method, url}
});
export const apiSuccess = ({response}) => ({
type: API_SUCCESS,
payload: response
});

export const postSuccess = ({response}) => ({
type: POST_SUCCESS,
payload: response
});

export const dashboardSuccess = ({response}) => ({
type: DASHBOARD_SUCCESS,
payload: response
});

export const apiFailure = ({error}) => ({
type: API_FAILURE,
payload: error
});
53 changes: 53 additions & 0 deletions src/actions/tasks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { SET_LOADER } from "./ui";

// feature name
export const TASKS = '[TASKS]';

export const USER_TASKS = `[USER_TASKS]`;

// action types
// command actions
export const FETCH_TASKS = `${TASKS} FETCH`;

export const FETCH_USER_TASKS = `${USER_TASKS} FETCH`;

export const PUT_TASK = `${TASKS} PUT`;

// document actions
export const SET_TASKS = `${TASKS} SET`;

export const ADD_TASKS = `${TASKS} ADD`;

export const DASHBOARD_TASKS = `${TASKS} DASHBOARD`;

export const fetchTasks = ({query}) => ({
type: FETCH_TASKS,
payload: query
});

export const setTasks = ({list}) => ({
type: SET_TASKS,
payload: list
});

export const addTasks = ({task}) => ({
type: ADD_TASKS,
payload: task
});

export const fetchUserTasks = (query) => {
return {
type: FETCH_USER_TASKS,
payload: query
};
};

export const updateTask = ({task}) => ({
type: PUT_TASK,
payload: task
});

export const countTasks = ({list}) => ({
type: DASHBOARD_TASKS,
payload: list
});
6 changes: 6 additions & 0 deletions src/actions/ui.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
// action types
export const SET_LOADER = 'SET_LOADER';
export const SET_NOTIFICATION = 'SET_NOTIFICATION';

export const setLoader = (showLoader) => ({
type: SET_LOADER,
payload: showLoader
});

export const setNotification = ({error}) => ({
type: SET_NOTIFICATION,
payload: error
});
31 changes: 31 additions & 0 deletions src/components/NavigationBar/NavigationBar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";
import NavigationBar from ".";
import { shallow } from 'enzyme';

// Enzyme adapter configuration
import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import { act } from "react-dom/test-utils";

Enzyme.configure({ adapter: new Adapter() });

let wrapper = null;

beforeEach(() => {
// Variable setting
});

afterEach(() => {
// destroy some resources
// wrapper.unmount();
});

describe('', () => {
it('Render 8 <ListItemLink /> components for two drawers', () => {
act(() => {
wrapper = shallow(<NavigationBar />);
});
console.log(wrapper.debug());
expect(wrapper.find('ListItemLink')).toHaveLength(8);
});
});
59 changes: 59 additions & 0 deletions src/components/Toggle/Toggle.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import Toggle from '.';
import { act } from "react-dom/test-utils";
import { render } from 'react-dom';
import { fireEvent, screen } from '@testing-library/react';

import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });

let container = null;
let toggleCallback = () => jest.fn();

beforeEach(() => {
// Variable setting
container = document.createElement('div');
document.body.appendChild(container);
});

afterEach(() => {
// destroy some resources
container.remove();
container = null;
});

describe('Render <Toggle /> component', () => {
it('Renders <Toggle /> with label "My Label"', () => {
act(() => {
render(<Toggle label="My Label" />, container);
});
expect(container.textContent).toContain('My Label');
});

it('Renders <Toggle /> deactive by default', () => {
act(() => {
render(<Toggle label="My Label" />, container);
});
expect(container.querySelector('input[type="checkbox"]').checked).toEqual(false);
});

it('Should change to active the <Toggle /> after dispatch click', () => {
act(() => {
render(<Toggle label="My Label" onToggle={toggleCallback} />, container);
fireEvent.click(screen.getByTestId('toggle'));
});
expect(container.querySelector('input[type="checkbox"]').checked).toEqual(true);
});

it('Should change to inactive the <Toggle active={true} /> after dispatch click', () => {
act(() => {
render(<Toggle label="My Label" onToggle={toggleCallback} active={true} />, container);
});
act(() => {
fireEvent.click(screen.getByTestId('toggle'));
});
expect(container.querySelector('input[type="checkbox"]').checked).toEqual(false);
});
});
1 change: 1 addition & 0 deletions src/components/Toggle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Toggle = ({ label, onToggle, active }) => {
return (
<FormControlLabel control={
<Switch
data-testid="toggle"
onChange={onToggle}
defaultChecked={active}
/>
Expand Down
79 changes: 79 additions & 0 deletions src/middlewares/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { apiFailure, apiSuccess, dashboardSuccess , postSuccess, API_START, API_POST, API_SELF_START, API_PUT, API_DASHBOARD} from "../actions/api";

export const apiMiddleware = ({dispatch}) => (next) => (action) => {
next(action);
switch(action.type) {
case API_START: {
const { method, body, url } = action.meta;
fetch(url, { method: method, body: body })
.then(response => response.json())
.then(data => {
dispatch(apiSuccess({response: data}));
})
.catch(function(error) {
dispatch(apiFailure({error: error}));
});
break;
}
case API_SELF_START: {
const { method, body, url } = action.meta;
fetch(url, { method: method })
.then(response => response.json())
.then(data => {
dispatch(apiSuccess({response: data.filter(item => item.user === body.user)}));
})
.catch(function(error) {
dispatch(apiFailure({error: error}));
});
break;
}
case API_POST: {
fetch(action.meta.url, {
method: action.meta.method,
body: JSON.stringify(action.payload),
headers: { 'Content-Type': 'application/json' }
})
.then(data => {
dispatch(postSuccess({response: data}));
})
.catch(function(error) {
dispatch(apiFailure({error: error}));
});
break;
}
case API_PUT: {
fetch(action.meta.url, {
method: action.meta.method,
body: JSON.stringify(action.payload),
headers: { 'Content-Type': 'application/json' }
})
.then(data => {
dispatch(postSuccess({response: data}));
})
.catch(function(error) {
dispatch(apiFailure({error: error}));
});
break;
}
case API_DASHBOARD: {
fetch(action.meta.url, { method: action.meta.method, body: action.meta.body })
.then(response => response.json())
.then(data => {
const completedTasks = data.filter(item => item.completed === true);
const uncompletedTasks = data.filter(item => item.completed === false);
dispatch(dashboardSuccess(
{response: [
{ argument: 'Completed', value: completedTasks.length},
{ argument: 'Uncompleted', value: uncompletedTasks.length}
]}
));
})
.catch(function(error) {
dispatch(apiFailure({error: error}));
});
break;
}
default:
break;
}
}
Loading