Skip to content

Commit

Permalink
Merge pull request #22 from flemton/feature/add-cars
Browse files Browse the repository at this point in the history
Request to merge Feature/add cars into development
  • Loading branch information
flemton authored Dec 17, 2023
2 parents 8709123 + d012d64 commit 0350cf9
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Login from './components/Session/Login';
import Register from './components/Session/Register';
import AddReservation from './pages/AddReservation/AddReservation';
import Session from './components/Session/Session';
import CarDetails from './components/CarDetails/CarDetails';

function App() {
return (
Expand All @@ -19,6 +20,7 @@ function App() {
<Route path="/addcar" element={<AddCar />} />
<Route path="/user_reservations" element={<ReservationList />} />
<Route path="/reserve" element={<AddReservation />} />
<Route path="/car-details" element={<CarDetails />} />
</Routes>
</Router>
);
Expand Down
147 changes: 102 additions & 45 deletions src/components/CarDetails/CarDetails.jsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,111 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useNavigate } from 'react-router-dom';
import colorRosetta from './color-rosetta.png';

const CarDetails = () => (
<>
<div className="car-details container-fluid bg-white rounded-3 p-3 shadow-4-strong">
<div className="text-end mt-2">
<h2 className="m-0">Tesla model X</h2>
<p className="tiny-font">£0.00 deposit upon any Car</p>
</div>
const CarDetails = ({ car }) => {
const navigate = useNavigate();

return (
<>
<div className="car-details container-fluid bg-white rounded-3 p-3 shadow-4-strong">
<div className="text-end mt-2">
<h2 className="m-0">{car.name}</h2>
<p className="tiny-font">
£
{car.finance_fee}
{' '}
deposit upon any Car
</p>
</div>

<table className="table table-striped tiny-font mt-3 mb-2">
<tbody>
<tr>
<td>Finance Fee:</td>
<td className="text-end">£0.00</td>
</tr>
<tr>
<td>Option to Purchase Fee:</td>
<td className="text-end">£0.00</td>
</tr>
<tr>
<td>Total Amount Payable:</td>
<td className="text-end">£ 0.00</td>
</tr>
<tr>
<td>Duration:</td>
<td className="text-end">36 Months</td>
</tr>
</tbody>
</table>
<p>
<span className="fw-bold m-0">5.29 APR</span>
&nbsp;Representative
</p>

<div className="text-center mx-3 my-4">
<p className="fw-bold tiny-font">
Discover more models&nbsp;
<span>&#62;</span>
<table className="table table-striped tiny-font mt-3 mb-2">
<tbody>
<tr>
<td>Finance Fee:</td>
<td className="text-end">
£
{car.finance_fee}
</td>
</tr>
<tr>
<td>Option to Purchase Fee:</td>
<td className="text-end">
£
{car.option_to_purchase_fee}
</td>
</tr>
<tr>
<td>Total Amount Payable:</td>
<td className="text-end" type="currency">
£
{car.total_amount_payable}
</td>
</tr>
<tr>
<td>Duration:</td>
<td className="text-end">
{car.duration}
{' '}
Months
</td>
</tr>
</tbody>
</table>
<p>
<span className="fw-bold m-0">5.29 APR</span>
&nbsp;Representative
</p>
<img src={colorRosetta} alt="Example" />
</div>

<div className="text-center my-2">
<button className="btn btn-dark px-5 text-white" type="button">
Reserve
</button>
<div className="text-center mx-3 my-4">
<p className="fw-bold tiny-font">
Discover more models&nbsp;
<span>&#62;</span>
</p>
<img src={colorRosetta} alt="Example" />
</div>

<div className="text-center my-2">
<button className="btn btn-dark px-5 text-white" type="button">
Reserve
</button>
</div>
</div>
</div>
</>
);
<button
className="btn btn-toolbar text-btn-white rounded-back-btn fs-5"
onClick={() => navigate('/home')}
type="button"
>
&laquo;
</button>
</>
);
};

CarDetails.propTypes = {
car: PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
image_url: PropTypes.string.isRequired,
finance_fee: PropTypes.number.isRequired,
option_to_purchase_fee: PropTypes.number.isRequired,
total_amount_payable: PropTypes.number.isRequired,
duration: PropTypes.number.isRequired,
}),
};

CarDetails.defaultProps = {
car: {
id: 0,
name: '',
description: '',
image_url: '',
finance_fee: 0,
option_to_purchase_fee: 0,
total_amount_payable: 0,
duration: 0,
},
};

export default CarDetails;
94 changes: 94 additions & 0 deletions src/components/CarsCard/CarsCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
h6,
h2 {
margin-bottom: 0 !important;
}

.card-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}

.car-card {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.car-image {
height: 250px;
max-width: 250px;
border-radius: 50%;
}

.description-text {
font-size: 12px;
font-weight: 300;
}

.text-size {
font-size: 12px;
font-weight: 300;
}

.long-description {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.custom {
margin-top: 1rem !important;
max-height: 25px;
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.custom-mobile-view {
margin-top: 1rem;
}

@media screen and (min-width: 767px) {
.text-size {
font-size: 10px;
font-weight: 300;
}

.custom-h {
min-height: 60px;
}

.long-description {
overflow: visible;
text-overflow: inherit;
white-space: inherit;
}
}

@media screen and (min-width: 1000px) {
.text-size {
font-size: 14px;
}

.card-name {
font-size: 20px;
}

.custom-h {
min-height: 60px;
}
}

@media screen and (min-width: 1200px) {
.text-size {
font-size: 14px;
}

.card-name {
font-size: 24px;
}
}
85 changes: 85 additions & 0 deletions src/components/CarsCard/CarsCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import CarDetails from '../CarDetails/CarDetails';
import deleteCar from '../../redux/requests/deleteCar';
import './CarsCard.css';

const CarsCard = ({ cars }) => {
const dispatch = useDispatch();
const deleting = useSelector((state) => state.car.deleting);
const [selectedCar, setSelectedCar] = useState(null);

const handleCarClick = (car) => {
setSelectedCar(car);
};

const handleGoBack = () => {
setSelectedCar(null);
};

return (
<div>
{!selectedCar && (
<div>
<div>
<h2>LATEST MODELS</h2>
<p>Please Select a Car Model</p>
</div>
</div>
)}
{selectedCar ? (
<CarDetails car={selectedCar} onGoBack={handleGoBack} />
) : (
<div className="card-container">
{cars?.map((car) => (
<div className="h-100 car-card" key={car.id} onClick={() => handleCarClick(car)}>
<img src={car.image_url} alt={car.name} className="car-image h-40" />
<h6 className="card-name">{car.name}</h6>
<div className="custom pb-1">
<p className="m-0 p-0 text-black-50 text-size long-description custom-h">
{car.description}
</p>
{deleting ? (
<div className="custom-mobile-view">
<button
type="button"
className="btn btn-outline-danger btn-sm my-1"
onClick={() => dispatch(deleteCar(car.id))}
>
Delete
</button>
</div>
) : (
<div className="custom-mobile-view">
<button
type="button"
className="btn btn-outline-primary btn-sm"
>
View Details
</button>
</div>
)}
</div>
</div>
))}
</div>
)}
</div>
);
};

CarsCard.propTypes = {
cars: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
image_url: PropTypes.string.isRequired,
}),
).isRequired,
};

export default CarsCard;
30 changes: 30 additions & 0 deletions src/components/Main/Main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import CarsCard from '../CarsCard/CarsCard';
import getCars from '../../redux/requests/getCars';

const Main = () => {
const cars = useSelector((state) => state.car?.cars);
const navigate = useNavigate();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCars());
}, []);

const handleCarClick = (carId) => {
navigate(`/car-details/${carId}`);
};

return (
<div>
<div>
<div>
<CarsCard cars={cars} onCarClick={handleCarClick} />
</div>
</div>
</div>
);
};

export default Main;
Loading

0 comments on commit 0350cf9

Please sign in to comment.