Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e776619
multiple dropdown selection button
Suhas-H-C Jun 24, 2024
66c3f01
used context to fetch the state and update the existing
Suhas-H-C Jul 14, 2024
310ecfe
tests added
Suhas-H-C Jul 14, 2024
a6b254f
Warning fixes on test cases
Suhas-H-C Jul 14, 2024
862d464
axios call integration
Suhas-H-C Jul 14, 2024
cb9c898
Merge pull request #2 from Suhas-H-C/feature/axios
Suhas-H-C Jul 14, 2024
57eb0fe
Dynamic navigation from screen 1 to screen 2
Suhas-H-C Aug 1, 2024
b88930f
tests added with configuration
Suhas-H-C Aug 1, 2024
4f9c788
Merge pull request #3 from Suhas-H-C/feature/dynamic_navigation
Suhas-H-C Aug 1, 2024
f4f31b1
Added DataGrid and API call
Suhas-H-C Aug 1, 2024
b2ac223
test configs added with enhanced test, need to add more tests in next…
Suhas-H-C Aug 2, 2024
86f2680
tests for send button
Suhas-H-C Aug 2, 2024
ed2ff96
Added tests for User drop down component
Suhas-H-C Aug 2, 2024
4310cc1
audited packages
Suhas-H-C Aug 2, 2024
63af2bc
package lock file
Suhas-H-C Aug 2, 2024
ec43743
Merge pull request #4 from Suhas-H-C/feature/dynamic_navigation
Suhas-H-C Aug 2, 2024
2187f07
App booting fixes
Suhas-H-C Aug 3, 2024
94fa82d
Added tests for Client dashboard
Suhas-H-C Aug 3, 2024
e9a144f
Merge pull request #5 from Suhas-H-C/feature/dynamic_navigation
Suhas-H-C Aug 3, 2024
8c4dc85
Added json server to form an endpoint for testing
Suhas-H-C Aug 8, 2024
5ec8fed
Merge pull request #7 from Suhas-H-C/feature/json-server
Suhas-H-C Aug 8, 2024
72901cf
tests refactored part-1
Suhas-H-C Dec 23, 2024
f5146fb
tests refactoring part-2
Suhas-H-C Dec 23, 2024
485a13a
Merge pull request #9 from Suhas-H-C/feature/refactoring-1
Suhas-H-C Dec 23, 2024
adf1d0e
gitignore updated
Suhas-H-C Dec 23, 2024
4258f40
Merge pull request #10 from Suhas-H-C/feature/refactoring-1
Suhas-H-C Dec 23, 2024
46f7572
Added back navigation functionality with tests
Suhas-H-C Dec 23, 2024
fe2e7e5
Added App.test.js and some more assertions
Suhas-H-C Dec 23, 2024
3f3e7c2
Merge pull request #11 from Suhas-H-C/feature/back_navigation_button
Suhas-H-C Dec 23, 2024
5451383
Added tests for service layer
Suhas-H-C Dec 23, 2024
b9dac46
Merge pull request #12 from Suhas-H-C/feature/back_navigation_button
Suhas-H-C Dec 23, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
package-lock.json

# testing
/coverage
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/d
### `npm run build` fails to minify

This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

### JSON Server

For installing json-server use [npm i -g -json-server]
For starting the json server locally use [npx json-server src/tests/utils/users.json --port 3030]
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: ["@babel/preset-env", "@babel/react"],
};
22 changes: 22 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const esModules = [
"@mui",
"@material-ui",
"rc-.+?",
"axios",
"@babel/runtime",
].join("|");

module.exports = {
verbose: true,
testEnvironment: "jsdom",
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
moduleDirectories: ["node_modules", "src"],
moduleNameMapper: {
"\\.(styl|less|sass|png|jpg|ttf|woff|woff2|css|scss|svg)$":
"identity-obj-proxy",
},
coverageDirectory: "coverage",
transformIgnorePatterns: [`/node_modules/(?!${esModules}).+(js|jsx|ts|tsx)$`],
watchPathIgnorePatterns: ["<rootDir>/node_modules/"],
setupFiles: ["<rootDir>/src/setupTests.js"],
};
10,067 changes: 4,963 additions & 5,104 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.15.14",
"@mui/x-data-grid": "^7.11.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.7.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
Expand Down
13 changes: 11 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { useContext } from "react";
import "./App.css";
import BackNavigationButton from "./component/BackNavigationButton";
import ClientDashboard from "./component/ClientDashboard";
import UserDropDown from "./component/UserDropDown";
import { UserDropDownContext } from "./context/UserDropDownContextProvider";

function App() {
return (
const { state, clientDashboard } = useContext(UserDropDownContext);

return clientDashboard.parentPage ? (
<UserDropDown />
) : (
<>
<UserDropDown />
<BackNavigationButton />
<ClientDashboard name={state.selectedUser} />
</>
);
}
Expand Down
29 changes: 29 additions & 0 deletions src/component/BackNavigationButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Button } from "@mui/material";
import React, { useContext } from "react";
import { UserDropDownContext } from "../context/UserDropDownContextProvider";

const BackNavigationButton = ({ name }) => {
const { setClientDashboard } = useContext(UserDropDownContext);

const handleNavigation = () => {
setClientDashboard({
childPage: false,
parentPage: true,
});
};

return (
<Button
type="button"
style={{ marginTop: 10 }}
color="info"
variant="contained"
data-testid="back-button-type-testid"
onClick={handleNavigation}
>
Back
</Button>
);
};

export default BackNavigationButton;
60 changes: 60 additions & 0 deletions src/component/ClientDashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Box } from "@mui/material";
import { DataGrid } from "@mui/x-data-grid";
import React, { useContext, useEffect, useState } from "react";
import { UserDropDownContext } from "../context/UserDropDownContextProvider";
import { EMPTY_ARRAY } from "../constant/Constant";

const ClientDashboard = ({ name }) => {
const { fetchGridData } = useContext(UserDropDownContext);
const [row, setRow] = useState(EMPTY_ARRAY);

useEffect(() => {
(async () => {
let gridData = await fetchGridData();
setRow(gridData);
})();
}, EMPTY_ARRAY);

const columns = [
{ field: "userId", headerName: "User ID", width: 90 },
{
field: "id",
headerName: "ID",
width: 150,
},
{
field: "title",
headerName: "Title",
width: 150,
},
{
field: "completed",
headerName: "Completed",
width: 110,
},
];

return (
<>
<Box sx={{ height: 400, width: "100%" }}>
<div>Welcome {name[0]} and others</div>
<DataGrid
rows={row}
columns={columns}
initialState={{
pagination: {
paginationModel: {
pageSize: 5,
},
},
}}
pageSizeOptions={[5]}
data-testid="data-grid-testid"
disableRowSelectionOnClick
/>
</Box>
</>
);
};

export default ClientDashboard;
31 changes: 18 additions & 13 deletions src/component/UserDropDown.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Autocomplete, Button, TextField } from "@mui/material";
import React, { useEffect, useState } from "react";
import React, { useContext, useEffect } from "react";
import "../css/UserDropDown.css";
import getUsers from "../service/DropDownService";
import { UserDropDownContext } from "../context/UserDropDownContextProvider";
import { EMPTY_ARRAY } from "../constant/Constant";

const UserDropDown = () => {
const url = "https://jsonplaceholder.typicode.com/users";
const [state, setState] = useState({
username: [],
selectedUser: [],
isButtonDisabled: true,
});
const { state, setState, fetchUserDetails, setClientDashboard } =
useContext(UserDropDownContext);

getUsers(url, setState);
useEffect(() => {
(async () => {
let response = await fetchUserDetails();
let names = response.map((user) => user.name);
setState((prev) => ({ ...prev, username: names }));
})();
}, EMPTY_ARRAY);

const handleChange = (event, newValue) => {
let showButton = newValue.length === 0 ? true : false;
Expand All @@ -21,8 +24,10 @@ const UserDropDown = () => {
};

const storeUsers = () => {
//TODO - can further call backend API with the logged payload
console.log(state);
setClientDashboard({
childPage: true,
parentPage: false,
});
};

return (
Expand All @@ -35,15 +40,15 @@ const UserDropDown = () => {
value={state.selectedUser}
sx={{ width: 500 }}
onChange={handleChange}
data-testid="my-user-dropdown"
data-testid="user-dropdown-type-testid"
renderInput={(params) => <TextField {...params} label="Select users" />}
/>
<Button
type="button"
style={{ marginTop: 10 }}
color="info"
variant="contained"
data-testid="send-button"
data-testid="send-button-type-testid"
onClick={storeUsers}
disabled={state.isButtonDisabled}
>
Expand Down
6 changes: 6 additions & 0 deletions src/constant/Constant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const USERS_ENDPOINT = "https://jsonplaceholder.typicode.com/users";
export const TODOS_ENDPOINT = "https://jsonplaceholder.typicode.com/todos";
export const HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}
export const EMPTY_ARRAY = [];
export const EMPTY_OBJECT = {};
export const GET = "GET";
10 changes: 10 additions & 0 deletions src/context/InitialState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const userInitialState = {
username: [],
selectedUser: [],
isButtonDisabled: true,
};

export const viewForAdmin = {
childPage: false,
parentPage: true,
};
36 changes: 36 additions & 0 deletions src/context/UserDropDownContextProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { createContext, useState } from "react";
import { TODOS_ENDPOINT, USERS_ENDPOINT } from "../constant/Constant";
import getUsers, { getGridData } from "../service/DropDownService";
import { userInitialState, viewForAdmin } from "./InitialState";

export const UserDropDownContext = createContext();

const UserDropDownContextProvider = ({ children }) => {
const [state, setState] = useState(userInitialState);
const [clientDashboard, setClientDashboard] = useState(viewForAdmin);

const fetchUserDetails = async () => {
return await getUsers(USERS_ENDPOINT);
};

const fetchGridData = async () => {
return await getGridData(TODOS_ENDPOINT);
};

return (
<UserDropDownContext.Provider
value={{
state,
setState,
fetchUserDetails,
fetchGridData,
clientDashboard,
setClientDashboard,
}}
>
{children}
</UserDropDownContext.Provider>
);
};

export default UserDropDownContextProvider;
17 changes: 10 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import UserDropDownContextProvider from "./context/UserDropDownContextProvider";
import "./index.css";
import reportWebVitals from "./reportWebVitals";

const root = ReactDOM.createRoot(document.getElementById('root'));
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
<UserDropDownContextProvider>
<App />
</UserDropDownContextProvider>
</React.StrictMode>
);

Expand Down
14 changes: 14 additions & 0 deletions src/service/ApiFetchConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import axios from "axios";

export async function fetchResponse(url, method, headers, body) {
return await axios({ url, method, headers, data: body })
.then((response) => handleResponse(response))
.then((data) => data)
.catch((error) => console.error(error));
}

export async function handleResponse(response) {
if (response.status === 200 || response.status === 201) {
return response;
}
}
30 changes: 20 additions & 10 deletions src/service/DropDownService.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
const getUsers = (url, setState) => {
fetch(url)
.then((response) => response.json())
.then((result) => {
let names = result.map((user) => user.name);
setState((prev) => {
return { ...prev, username: names };
});
})
.catch((err) => console.warn(err));
import { fetchResponse } from "./ApiFetchConfig";

const getUsers = async (url) => {
const header = {
Accept: "application/json",
"Content-Type": "application/json",
};
const body = {};
let response = await fetchResponse(url, "GET", header, body);
return response.data;
};

export const getGridData = async (url) => {
const header = {
Accept: "application/json",
"Content-Type": "application/json",
};
const body = {};
let response = await fetchResponse(url, "GET", header, body);
return response.data;
};

export default getUsers;
22 changes: 17 additions & 5 deletions src/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
import React from "react";

global.React = React;

Object.defineProperty(window, "matchMedia", {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onChange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
Loading