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

Earth | Christina & Genevieve #4

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
24eeeef
Added route to Search component
christinaminh Jan 19, 2021
2357b60
Added SearchResultItem to display search results for API call
christinaminh Jan 20, 2021
5de045f
Add styling to search result items
christinaminh Jan 20, 2021
5a9eb89
render list customer components from static list
geneminde Jan 20, 2021
c8498a8
add styles to customer components
geneminde Jan 20, 2021
dc1ae85
From the video search results, I can add a video from the search resu…
christinaminh Jan 20, 2021
6e1d8b0
render customer list from api call
geneminde Jan 20, 2021
2f6b71a
Merge branch 'master' into customers
geneminde Jan 20, 2021
92911a0
Merge pull request #1 from christinaminh/customers
geneminde Jan 20, 2021
1561436
fix missing brace
geneminde Jan 20, 2021
31dd49b
Changed styling for search results to match customer list styling. Co…
christinaminh Jan 20, 2021
6e42dc1
add state for selected customer
geneminde Jan 20, 2021
56f6588
Merge branch 'master' into customers
geneminde Jan 20, 2021
19d157c
Added error message parsing function and changed output of error mess…
christinaminh Jan 20, 2021
4aeafa2
style navbar
geneminde Jan 20, 2021
5a52874
merge customer select
geneminde Jan 20, 2021
91172c3
resolve conflicts
geneminde Jan 20, 2021
7f4c487
select video callback/state
geneminde Jan 20, 2021
90b6b2e
Added VideoLibary and Video Components. From the home page, I can nav…
christinaminh Jan 20, 2021
c02a4a1
Merged with origin master
christinaminh Jan 20, 2021
ea38bff
Installed and imported react-bootstrap. Changed styling of video and …
christinaminh Jan 20, 2021
3e57651
Change styling of Add Video to Library button on search page
christinaminh Jan 20, 2021
eeaa003
select a video
geneminde Jan 20, 2021
7f0b854
select video
geneminde Jan 20, 2021
6fc995b
Made Video component buttons to select video from video library
christinaminh Jan 20, 2021
75e5813
Merge pull request #2 from christinaminh/select-video
geneminde Jan 20, 2021
8c3373b
Removed conflicts in Video Components from merge
christinaminh Jan 20, 2021
a494012
Refactored Video and SearchResultItem component to just Video component
christinaminh Jan 21, 2021
31778d9
Changed styling of add video button on search page
christinaminh Jan 21, 2021
09d95f3
Added styling to error message with Alert component from bootstrap
christinaminh Jan 21, 2021
0425bfd
add rental checkout
geneminde Jan 21, 2021
36a512e
merge master
geneminde Jan 21, 2021
9e2f267
alert styling
geneminde Jan 21, 2021
8faf561
Merge pull request #3 from christinaminh/rental
geneminde Jan 21, 2021
d33b01c
Matched error message timeout to rental message timeout
christinaminh Jan 21, 2021
0c9c9ce
Display Video and Customer List in alphabetical order by title and name
christinaminh Jan 21, 2021
48ac73f
remove unused import
geneminde Jan 21, 2021
874e032
remove comments
geneminde Jan 21, 2021
36fd97f
merge changes
geneminde Jan 21, 2021
d0c0c74
Added proptypes to components
christinaminh Jan 21, 2021
c1b3730
merged conflict
christinaminh Jan 21, 2021
f2d21d8
Removed setErrorMessage for successful video library call
christinaminh Jan 22, 2021
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
16,063 changes: 9,767 additions & 6,296 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,23 @@
"version": "0.1.1",
"private": true,
"dependencies": {
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"moment": "^2.29.1",
"react": "^17.0.1",
"react-bootstrap": "^1.4.3",
"react-dom": "^17.0.1",
"react-moment": "^1.1.1",
"react-onclickoutside": "^6.9.1",
"react-router-bootstrap": "^0.25.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1"
},
"devDependencies": {
"gh-pages": "^3.1.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.3",
"@testing-library/user-event": "^12.6.0"
"@testing-library/user-event": "^12.6.0",
"gh-pages": "^3.1.0"
},
"scripts": {
"start": "PORT=3001 react-scripts start",
Expand Down
46 changes: 36 additions & 10 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
text-align: center;
}

.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}

.App-header {
background-color: #222;
height: 150px;
Expand All @@ -18,11 +13,42 @@
font-size: 1.5em;
}

.App-intro {
font-size: large;
html {
box-sizing: border-box;
}

*, *::before, *::after {
box-sizing: inherit;
padding: 0;
margin: 0;
}


.nav-links {
list-style: none;
display: flex;
background-color: black;

}

nav ul li {
padding: 20px;
}

@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
nav ul li a {
color: white;
text-decoration: none;
}

.selected {
color: rgb(158, 152, 152);
}
.current {
border-bottom: 4px solid white;
}


ul {
list-style-type: none;
}

137 changes: 123 additions & 14 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,130 @@
import React, { Component } from 'react';
import logo from './logo.svg';
/* eslint-disable camelcase */
import React, { useState } from 'react';
import axios from 'axios'
import './App.css';
import { BrowserRouter as Router, Switch, Route, NavLink} from 'react-router-dom';
import {Alert, Button} from 'react-bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css';
import Search from './components/Search/Search'
import CustomerList from './components/CustomerList'
import VideoLibrary from './components/VideoLibrary/VideoLibrary'

class App extends Component {
render() {


const App = () => {
const BASE_URL = 'http://localhost:3000/'

const [errorMessage, setErrorMessage] = useState(null)
const [videoLibrary, setVideoLibrary] = useState([])
const [selectedCustomer, setSelectedCustomer] = useState(null)
const [selectedVideo, setSelectedVideo] = useState(null)
const [rentalMessage, setRentalMessage] = useState(null)

const addVideo = (video) => {
axios.post(BASE_URL+'videos', video)
.then( response => {
const newVideoList = [...videoLibrary, response.data]
setVideoLibrary(newVideoList)
setTimeout(() => setErrorMessage(null), 6000);
})
.catch( error => {
const errors = error.response.data.errors
setErrorMessage(errors)
setTimeout(() => setErrorMessage(null), 6000);
})
};

const setCustomer = (id, name) => {
if (selectedCustomer && id === selectedCustomer.id) {
setSelectedCustomer(null)
} else {
setSelectedCustomer({id: id, name: name})
}
};

const setVideo = (title) => {
if (selectedVideo && title === selectedVideo) {
setSelectedVideo(null)
} else {
setSelectedVideo(title)
}
}


const rentVideo = () => {
axios.post(`${BASE_URL}rentals/${selectedVideo}/check-out`, {customer_id: selectedCustomer.id})
.then(() => {
setRentalMessage(`Rental successfully created`);
setTimeout(() => setRentalMessage(''), 6000);
setSelectedCustomer(null);
setSelectedVideo(null);
})
.catch((error) => {
setRentalMessage(error.message);
setTimeout(() => setRentalMessage(''), 6000)
})
}

const parseErrorMessages = (errors) => {
return (
<ul>
{
Object.entries(errors).map(([key, value]) => (
<li>{value}</li>
))
}
</ul>
);
}

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>

<Router>
<div className='App'>
<header className='App-header'>

</header>

<nav>
<ul className='nav-links'>
<li>
<NavLink exact activeClassName='current' to='/'>Home</NavLink>
</li>
<li>
<NavLink exact activeClassName='current' to='/library'>Video List</NavLink>
</li>
<li>
<NavLink exact activeClassName='current'to='/customers'>Customer List</NavLink>
</li>
<li>
<NavLink exact activeClassName='current' to='/search'>Search The Movie DB</NavLink>
</li>
{selectedCustomer ? <li className='selected'>Customer: {selectedCustomer.name}</li> : ''}
{selectedVideo ? <li className='selected'>Video: {selectedVideo}</li> : ''}
{selectedCustomer && selectedVideo ? <li><Button variant="secondary" size="sm" onClick={() => {rentVideo()}}>Create Rental</Button></li> : ''}
</ul>
</nav>


{ rentalMessage ? <Alert variant='success'> {rentalMessage} </Alert> : null}
{ errorMessage ? <Alert variant='danger'>{parseErrorMessages(errorMessage)}</Alert> : null}

<Switch>
<Route path='/search'>
<Search setErrorMessage={setErrorMessage} addVideoCallback={addVideo} baseUrl={BASE_URL}/>
</Route>
<Route path='/customers'>
<CustomerList setCustomer={setCustomer} />
</Route>
<Route path='/library'>
<VideoLibrary baseUrl={BASE_URL} videoLibrary={videoLibrary} setVideoLibraryCallback={setVideoLibrary} setVideo={setVideo} setErrorMessage={setErrorMessage}/>
</Route>
</Switch>
</div>
</Router>
);
}
}



export default App;
20 changes: 20 additions & 0 deletions src/components/Customer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import './Customer.css'

const Customer = (props) => {

return(
<div className="customer">
<button onClick={() => {props.setCustomer(props.id, props.name)}}>select</button>
<h3 className="customer__content">{props.name}</h3>
</div>

)
};

Customer.propTypes = {
name: PropTypes.string.isRequired,
}

export default Customer;
4 changes: 4 additions & 0 deletions src/components/CustomerList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.customer-list {
display: flex;
flex-wrap: wrap;
}
36 changes: 36 additions & 0 deletions src/components/CustomerList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import Customer from './Customer';
import axios from 'axios';
import './CustomerList.css'

const CustomerList = (props) => {
const [customers, setCustomers] = useState([]);
const [errorMessage, setErrorMessage] = useState(null);

useEffect(() => {
axios.get('http://localhost:3000/customers?sort=name')
.then((response) => {
setCustomers(response.data)
})
.catch((error) => {
setErrorMessage(error.message);
});
},[]);

const customerComponents = customers.map((customer) => {
return(< Customer key={customer.id} name={customer.name} id={customer.id} setCustomer={props.setCustomer} />)
})

return(
<div className="customer-list">
{customerComponents}
{ errorMessage ? <div><h2>{errorMessage}</h2></div> : ''}
</div>
)};

CustomerList.propTypes = {
setCustomer: PropTypes.func.isRequired
}

export default CustomerList;
17 changes: 17 additions & 0 deletions src/components/Search/NewVideoForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.add-video-form {
padding-bottom: 1rem;
overflow: visible;
}

.add-video-form label {
font-size: medium;
}

.add-video-dropdown {
display: flex;
justify-content: space-evenly;
}

.add-video-dropdown *{
font-size: small;
}
51 changes: 51 additions & 0 deletions src/components/Search/NewVideoForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types';
import { Dropdown, DropdownButton, Button } from 'react-bootstrap'
import './NewVideoForm.css'


const NewVideoForm = ({video, addVideoCallback}) => {
const [startingInventory, setStartingInventory] = useState(0)
const [addedToLibrary, setAddedToLibrary] = useState(false)

const onAddToLibrary = (event) => {
const newVideo = {...video}
newVideo.inventory = event.target.value

addVideoCallback(newVideo)
setAddedToLibrary(true)
}

const showDropdown = () => {
return (
<div className='add-video-form'>
<h4><label>Stock Video</label></h4>
<div className='add-video-dropdown'>
<DropdownButton title={startingInventory}>
{[...Array(21).keys()].map(i => (
<Dropdown.Item onSelect={(eventKey) => {setStartingInventory(eventKey)}} value={i} eventKey={i} >{i}</Dropdown.Item>
))}
</DropdownButton>

<Button onClick={onAddToLibrary} value={startingInventory} variant="outline-secondary">Add to Library</Button>
</div>

</div>
)
}


return(
<div>
{addedToLibrary ? <Button variant="secondary" disabled>In Video Library</ Button> : showDropdown()}
</div>

)
}

NewVideoForm.propTypes = {
video: PropTypes.object.isRequired,
addVideoCallback: PropTypes.func.isRequired
}

export default NewVideoForm
11 changes: 11 additions & 0 deletions src/components/Search/Search.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.search-results {
display: flex;
flex-wrap: wrap;
justify-content: center;
}

.search {
display: flex;
flex-direction: column;
align-items: center;
}
Loading