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 - Ringo & Schanen #31

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
11d6c69
bundle install and add react router
ringolingo Jan 20, 2021
6b56381
add react router to App component
ringolingo Jan 20, 2021
8ece85b
define Customer component
ringolingo Jan 20, 2021
69824eb
implement CustomerList component with static data
ringolingo Jan 20, 2021
9a9d7bf
import CustomerList to App
ringolingo Jan 20, 2021
3b8552d
refactor prop names
ringolingo Jan 20, 2021
ac2f913
add axios, useEffect, useState to get customer data and pass to Custo…
ringolingo Jan 20, 2021
b1a5e44
Merge pull request #1 from schanenR/create-customer
ringolingo Jan 20, 2021
9424eb9
Video and VideoLibrary components built. Library rendering in browser.
schanenR Jan 20, 2021
602ea9f
Fixed merge conflict in App
schanenR Jan 20, 2021
cea298e
Fixed missed conflic in App.js
schanenR Jan 20, 2021
bbbd679
build SearchForm component to take in film title
ringolingo Jan 21, 2021
c2b1f9f
import SearchResultComponent to App
ringolingo Jan 21, 2021
3bc6574
build SearchResultsList component to make get request and render results
ringolingo Jan 21, 2021
c494b44
Video table button added, select funstionality in progress.
schanenR Jan 21, 2021
bd4fa01
Reverted select logic for completed and functioning table render.
schanenR Jan 21, 2021
8df209e
Select button for customer and video functioning.
schanenR Jan 21, 2021
c78be42
Merge commit
schanenR Jan 21, 2021
ef09f45
define addFilm function and update SearchResultList table render
ringolingo Jan 21, 2021
ad61991
define onAddFilm function and update button based on props
ringolingo Jan 21, 2021
744152a
resolve merge conflict in Video component with buildButton func
ringolingo Jan 21, 2021
720f0a8
fix bug in adding image_url to database
ringolingo Jan 21, 2021
0c50142
remove redundant button code
ringolingo Jan 21, 2021
8ed923d
Added Store component
schanenR Jan 21, 2021
bfcdbec
Moved customer and video selection up to new Store component.
schanenR Jan 21, 2021
224e1c4
Fixed add film with simple pull request.
schanenR Jan 21, 2021
8351058
add Bootstrap and css classes for button, navbar
ringolingo Jan 21, 2021
c2cfa3d
add alert css and change customer css
ringolingo Jan 21, 2021
ae8d905
change header and button appearance, delete comments
ringolingo Jan 21, 2021
a381269
Merge pull request #2 from schanenR/boostrap-branch
ringolingo Jan 21, 2021
9fd0dd1
Added Rental component frame
schanenR Jan 22, 2021
727c892
Merge from master
schanenR Jan 22, 2021
a73e6bb
Home page image rendering.
schanenR Jan 22, 2021
1108c0d
Check-in functioning.
schanenR Jan 22, 2021
3553b5a
Whoops
schanenR Jan 22, 2021
0c67395
Deleted uneeded css files
schanenR Jan 22, 2021
0731acf
Fixed url path again, don't know went wrong. Sry I'm tired : )
schanenR Jan 22, 2021
03533a5
Added CSS
schanenR 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*

yarn.lock
10,792 changes: 6,521 additions & 4,271 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
"version": "0.1.1",
"private": true,
"dependencies": {
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"react": "^17.0.1",
"react-bootstrap": "^1.4.3",
"react-dom": "^17.0.1",
"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
39 changes: 21 additions & 18 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
.App {
text-align: center;
.center {
display: block;
margin-left: auto;
margin-right: auto;
width: 55%;
}

.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.footer {
display: flex;
flex-direction: row;
justify-content: space-between;
left: 0;
bottom: 0;
width: 100%;
margin: 10px;

.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}

.App-title {
font-size: 1.5em;
.footer-div, .footer-div-button {
margin-left: 50px;
margin-right: 50px;
}

.App-intro {
font-size: large;
.footer-div-button {
margin-top: 15px;
}

@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
.selection-header {
color: #2887d1;
padding-bottom: 25px;
}
18 changes: 8 additions & 10 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React, { Component } from 'react';
import logo from './logo.svg';
import Store from './components/Store';

// import child components: search

import './App.css';



class App extends Component {

render() {
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>
<Store />
);
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/components/Customer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.card-subtitle {
line-height: 200%;
font-weight: bold;
}

.card-text {
line-height: 120%;
}
46 changes: 46 additions & 0 deletions src/components/Customer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import PropTypes from 'prop-types';
import './Customer.css';

const Customer = (props) => {

const onButtonClick = () => {
const selected = {
id: props.id,
name: props.name
}
props.selectCustomerCallback(selected);
}

return (
<div className="card">
<div className="card-body">
<h4 className="card-title">{props.name}</h4>
<h5 className="card-subtitle">Videos currently rented: {props.videosCheckedOutCount}</h5>
<p className="card-text">Customer since {props.registeredAt.slice(0, 4)}<br />
Account Credit: {props.accountCredit}<br/>
{props.phone}<br/>
{props.address}<br/>
{props.city}, {props.state} {props.postalCode}</p>
{props.isSelected? <button className="btn btn-primary selected" onClick={onButtonClick}>SELECTED</button> : <button className="btn btn-primary select" onClick={onButtonClick}>SELECT</button> }
</div>
</div>
)
}

Customer.propTypes = {
id: PropTypes.number,
name: PropTypes.string,
registeredAt: PropTypes.string,
address: PropTypes.string,
city: PropTypes.string,
state: PropTypes.string,
postalCode: PropTypes.string,
phone: PropTypes.string,
accountCredit: PropTypes.number,
videosCheckedOutCount: PropTypes.number,
isSelected: PropTypes.bool,
selectCustomerCallback: PropTypes.func
}

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

const CustomerList = (props) => {
const [customers, setCustomers] = useState([]);
const [error, setError] = useState('');


useEffect(() => {
axios.get(`http://localhost:3000/customers/`)
.then((response) => {
const allCustomers = [];
response.data.forEach((customer) => {
allCustomers.push(customer);
});
setCustomers(allCustomers);
})
.catch((error) => {
setError(`Error: ${error.response.statusText}`);
})
}, []);

const formatCustomer = customer => {
return <Customer
key={customer.id}
id={customer.id}
name={customer.name}
registeredAt={customer.registered_at}
address={customer.address}
city={customer.city}
state={customer.state}
postalCode={customer.postal_code}
phone={customer.phone}
accountCredit={customer.account_credit}
videosCheckedOutCount={customer.videos_checked_out_count}
selectCustomerCallback={props.selectCustomerCallback}
isSelected={props.selectedCustomer? customer.id === props.selectedCustomer.id : null}
/>
}

return (
<div>
{ customers.map(formatCustomer) }
{ error ? error : '' }
</div>
);
}

// PROPS? - should App hold the URL for the api call and pass it down to CustomerList?
CustomerList.propTypes = {
selectCustomerCallback: PropTypes.func,
selectedCustomer: PropTypes.object
};


export default CustomerList;
107 changes: 107 additions & 0 deletions src/components/Rental.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import scarecrow from '../scarecrow.jpg'
import axios from 'axios';

const Rental = (props) => {

const [error, setError] = useState('');
const [alert, setAlert] = useState('');

const returnDate = () => {
const dueDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)

const year = dueDate.getFullYear();
const month = dueDate.getMonth() + 1;
const day = dueDate.getDate();



return (
`${year}-${month}-${day}`
)
}

const rentVideo = () => {
if (props.video !== null && props.customer !== null) {

const date = returnDate();

axios.post(`http://localhost:3000/rentals/${props.video.title}/check-out?customer_id=${props.customer.id}&due_date=${date}`)
.then((response) => {
setAlert(`You have successfully rented ${props.video.title}!`);
setError('');

props.setSelectedCustomer(null);
props.setSelectedVideo(null);
})
.catch((error) => {
setError('Could not create a rental. Not enough inventory.');
setAlert('');
})
}
}

const returnVideo = () => {
if (props.video !== null && props.customer !== null) {
axios.post(`http://localhost:3000/rentals/${props.video.title}/return?customer_id=${props.customer.id}`)
.then((response) => {
setAlert(`Thank you for returning ${props.video.title}!`);
setError('');
// clear sessionContext after rental made
props.setSelectedCustomer(null);
props.setSelectedVideo(null);
})
.catch((error) => {
setError('Something went wrong, could not return video!');
setAlert('');
})
}
}

const rentalButtons = () => {
if (props.video !== null && props.customer !== null) {
return (
<div>
<button className="btn btn-primary mr-1" onClick={() => rentVideo()} >
Rent Movie
</button>
<button className="btn btn-primary mr-1" onClick={() => returnVideo()} >
Return Movie
</button>
</div>
)
}
}

return (
<div>
{ error ? <div className="alert alert-warning">{error}</div> : '' }
{ alert ? <div className="alert alert-success">{alert}</div> : '' }

<img className="center" src={scarecrow} alt="Scarecrowz Video" />;

<h3 className="selection-header text-center">Select a Video and Customer to Check-out or Check-in a VIDEO!</h3>
<div>
<div className="footer">
<div className="footer-div">
<p>Selected Video: <strong>{props.video === null ? 'no video selected' : props.video.title}</strong></p>
<p>Selected Customer: <strong>{props.customer === null ? 'no customer selected' : props.customer.name}</strong></p>
</div>
<div className="footer-div-button">
{rentalButtons()}
</div>
</div>
</div>
</div>
)
}

Rental.propTypes = {
video: PropTypes.object,
customer: PropTypes.object,
setSelectedCustomer: PropTypes.func,
setSelectedVideo: PropTypes.func
}

export default Rental;
34 changes: 34 additions & 0 deletions src/components/SearchForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';

const SearchForm = ({ onSubmitCallback }) => {
const [titleField, setTitleField] = useState('');

const onInputChange = (event) => {
setTitleField(event.target.value);
};

const onSubmitSearch = (event) => {
event.preventDefault();
if (titleField.length > 0) {
onSubmitCallback(titleField);
}
};

return (
<div className="search-form">
<h3>Need to add a movie to your library?</h3>
<form className="search-form__form" onSubmit={ onSubmitSearch } >
<label>Title:</label>
<input type="text" value={titleField} onChange={ onInputChange } />
<input type="submit" value="Search" className="btn btn-primary"/>
</form>
</div>
);
};

SearchForm.propTypes = {
onSubmitCallback: PropTypes.func.isRequired,
}

export default SearchForm;
Loading