Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS coding challenge submitted for assessment (Joel Chavoya) #37

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
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
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# dependencies
/src/client/node_modules/
/src/server/node_modules/

# IDEs and editors
.idea/

#System Files
.DS_Store
13 changes: 6 additions & 7 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Hey, welcome to the first coding challenge of your interview process, you'll be
## The Prereqs
This challenge assumes your knowledge or skills to leverage on the following topics,

- Vanilla JavaScript (or plain JavaScript)
- JavaScript
- NodeJS
- Express
- MongoDB
- Mongoose (or another nodejs based ORM for mongodb)
- RESTful APIs, webservices
- A client side MV* framwork or library (Angular1, Angular2, React(not an mvc, tho) )
- A client side MV* framwork or library (Angular1, Angular2, React(not an mv*, tho) )
- Code quality and testing

## The rules
Expand Down Expand Up @@ -41,9 +41,8 @@ You will be creating a simple server-client application so common nowadays, usin
- I need an exposed CRUD API to affect the Lists and Items entities using the correct HTTP verbs for each
- Create, update, remove, fetch all and fetch by id should be supported for lists and items (10 endpoints total)
- I need middleware to happen on each request validating that the user has a cookie named "auth" or not (log the value to output, we are not managing authentication of any kind just yet)

- I need a test suit testing the endpoints
- I need a test suit testing the middleware covering the cases where the user has a cookie named "auth", a cookie with another name or no cookie at all
- I need a test suite testing the endpoints
- I need a test suite testing the middleware covering the cases where the user has a cookie named "auth", a cookie with another name or no cookie at all


## The small print
Expand All @@ -53,5 +52,5 @@ Stuff that will be graded
Logic and code complexity ( How easy will my code be to maintain by someone else? Am I using good practices and/or design patterns? )
Code coverage ( Is my code tested? Are all scenarios considered? )
Requirement coverage ( Is the application doing what it is meant to be doing? )
Rule compliance ( Did i follow the few rules set on **The rules** ? )

Rule compliance ( Did i follow the few rules set on __The rules__ ? )

Empty file removed src/client/.gitkeep
Empty file.
15,025 changes: 15,025 additions & 0 deletions src/client/package-lock.json

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions src/client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-scripts": "2.1.1"
},
"proxy": "http://localhost:3001",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"devDependencies": {
"bootstrap": "^4.1.3",
"prop-types": "^15.6.2",
"reactstrap": "^6.5.0"
}
}
14 changes: 14 additions & 0 deletions src/client/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://localhost:8097"></script>
<meta charset="utf-8">
<title>MERN Coding Challenge</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
159 changes: 159 additions & 0 deletions src/client/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import React, { Component } from 'react';

import InputText from './components/stateless/InputText';
import InputButton from './components/stateless/InputButton';
import Lists from './components/stateless/Lists'

class App extends Component {

constructor(props) {

super(props);

this.state = {
listName: '',
lists: [],
itemIDCounter: 0,
listIDCounter: 0
};
}

componentDidMount() {
fetch('/test')
.then(res => res.json())
.then(lists => this.setState({ lists }));
}

//Gets name for new list from text field
getListName = (event) => {

let newValue = event.target.value

this.setState ({
listName: newValue
});
}

//Pushes new list into 'lists' array
createList = () => {

let listCounter = this.state.listIDCounter

if (this.state.listName) {

let existingLists = new Array(...this.state.lists)

let newList = {
listName: this.state.listName,
items: new Array(0),
listID: listCounter
}

existingLists.push(newList)
listCounter++

this.setState ({
lists: existingLists,
listIDCounter: listCounter,
listName: ''
})
}
}

//Creates a new item for a designated list
createListItem = (index) => {

let itemContent = prompt(`Write item for list number ${index} here:`)
let itemCounter = this.state.itemIDCounter

if (itemContent) {

let itemsArray = this.state.lists[index].items

let newValue = {
content: itemContent,
itemID: itemCounter
}

itemsArray.push(newValue)
itemCounter++

this.setState ({
lists: [...this.state.lists],
itemIDCounter: itemCounter
})
}
}

//Deletes an item from an existing list, receives the list index for 'lists' array and item number for 'items' array
deleteListItem = (listIndex, itemNo) => {

let itemsArray = this.state.lists[listIndex].items
const list = this.state.lists[listIndex].listName

let confirmation = window.confirm(`Are you sure you want to delete '${itemsArray[itemNo].content}' from list '${list}'?`)

if (confirmation) {

itemsArray.splice(itemNo, 1)

this.setState({
lists: [...this.state.lists]
})
}
}

//Edits a particular list item from an existing lists, receives the list index for 'lists' array and item number for 'items' array
editListItem = (listIndex, itemNo) => {

let itemsArray = this.state.lists[listIndex].items
const list = this.state.lists[listIndex].listName

let newValue = {
content: window.prompt(`Edit '${itemsArray[itemNo].content}' from list '${list}':`),
itemID: itemsArray[itemNo].itemID
}

if (newValue) {

itemsArray.splice(itemNo, 1, newValue)

this.setState ({
lists: [...this.state.lists]
})
}
}

render() {

return (
<div className='m-5'>
<div className='d-flex flex-column align-items-center justify-content-center app-input'>
<h2 className='text-center mb-4'>MERN Coding Challenge</h2>
<p className='h5'>Add a new list</p>
<InputText
className='my-2'
type='text'
id='list_name'
value={this.state.listName}
handleChange={this.getListName}
/>
<InputButton
handleClick={this.createList}
buttonText='Add new list'
buttonSize={'lg'}
buttonColor={'primary'}
/>
</div>
<Lists
listsArray={this.state.lists}
onAddNewItem={this.createListItem}
onDeleteItem={this.deleteListItem}
onEditItem={this.editListItem}
/>
</div>
);
}
}

export default App;
26 changes: 26 additions & 0 deletions src/client/src/components/stateless/InputButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'
import { Button } from 'reactstrap';
import PropTypes from 'prop-types';

const InputButton = (props) => {

const { handleClick, buttonText, buttonColor, buttonSize, className } = props

return (
<Button
onClick={handleClick}
color={buttonColor}
size={buttonSize}
className={className}>
{buttonText}
</Button>
)
}

InputButton.propTypes = {
handleClick: PropTypes.func.isRequired,
buttonText: PropTypes.string.isRequired,
buttonColor: PropTypes.string.isRequired
}

export default InputButton;
29 changes: 29 additions & 0 deletions src/client/src/components/stateless/InputText.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { Input } from 'reactstrap';
import PropTypes from 'prop-types';

const InputText = (props) => {

const { type, id, value, handleChange, className } = props

return (
<div>
<Input
className={className}
type={type}
id={id}
value={value}
onChange={handleChange}
/>
</div>
)
};

InputText.propTypes = {
type: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
handleChange: PropTypes.func.isRequired
};

export default InputText;
77 changes: 77 additions & 0 deletions src/client/src/components/stateless/Lists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { Row, Col } from 'reactstrap';
import PropTypes from 'prop-types';

import InputButton from './InputButton'

const Lists = (props) => {

const { listsArray, onAddNewItem, onDeleteItem, onEditItem } = props
const lists = Object.values(listsArray)

//Returns an array of the items in "lists" array
let renderedLists = lists.map((item, index) => {

//Returns an array of the items inside the "items" array
let itemsFromList = Object.values(lists[index].items)
let renderedItems = itemsFromList.map((v, i) => {

return (
<li className='lists-list-item list-group-item list-group-flush d-flex justify-content-between' key={i}>
<div>
<div className={"lists-list-number"}>{i+1}</div> {v.content}
</div>
<div>
<InputButton
handleClick={(e) => onEditItem(index, i)}
buttonText='Edit'
buttonSize={'sm'}
buttonColor={'secondary'}
className={'mr-2'}/>
<InputButton
handleClick={(e) => onDeleteItem(index, i)}
buttonText='Delete'
buttonSize={'sm'}
buttonColor={'warning'}/>
</div>
</li>
)
});

return (
<Col md='3' className='lists-list m-2' key={index}>
<div className='mb-3'>
<div className='h4 mb-0 text-center'>-- {lists[index].listName} --</div>
<div className='h6 mb-3 text-center'>List {index+1}</div>
</div>
<div className='mb-3'>
<ul className='list-group'>
{renderedItems}
</ul>
</div>
<div className='d-flex align-items-center justify-content-center'>
<InputButton
handleClick={(e) => onAddNewItem(index)}
buttonText='+ Add item'
buttonColor={'info'}
buttonSize={''}/>
</div>
</Col>
)
});

return (
<Row className='mt-5 d-flex justify-content-center align-items-center'>
{renderedLists}
</Row>
)
}

Lists.propTypes = {
onAddNewItem: PropTypes.func.isRequired,
onDeleteItem: PropTypes.func.isRequired,
onEditItem: PropTypes.func.isRequired,
listsArray: PropTypes.array.isRequired
}

export default Lists;
Loading