Skip to content
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
22,953 changes: 22,925 additions & 28 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions src/api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
* @param {string} apiUrl
* @return {Promise<Object>}
*/
export async function request(apiUrl) {
return apiUrl;
export async function request(vehicle) {
let finalData = {};
try {
const response = await fetch(vehicle.apiUrl);
finalData = {
...vehicle,
...(await response.json()),
};
} catch (err) {
console.log('Error :', err);
}
return finalData;
}

export function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
16 changes: 14 additions & 2 deletions src/api/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line no-unused-vars
import { request } from './helpers';
import { request, isEmpty } from './helpers';

/**
* Pull vehicles information
Expand All @@ -8,5 +8,17 @@ import { request } from './helpers';
*/
// TODO: All API related logic should be made inside this function.
export default async function getData() {
return [];
const response = await fetch('/api/vehicles.json');
const vehiclesData = await response.json();

const finalData = await Promise.allSettled(
vehiclesData.map((data) => request(data))
).then((results) => results.map((result) => {
if (result.status === 'fulfilled') {
return result.value;
}
return [];
}));

return finalData.filter((vehicle) => !isEmpty(vehicle) && vehicle.price);
}
44 changes: 44 additions & 0 deletions src/components/Modal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { useContext } from 'react';
import ReactDOM from 'react-dom';
import Vehicle from '../Vehicle';
import './style.scss';
import { ModalContext } from '../../contexts/ModalContext';

const Modal = () => {
const {
showModal, setModal, showDetails, setDetails
} = useContext(ModalContext);

const hide = () => {
setModal(!showModal);
setDetails('');
};
return showModal
? ReactDOM.createPortal(
<>
<div className="modal__overlay" />
<div className="modal__wrapper" tabIndex={-1}>
<div className="modal__body">
<div className="modal__header">
<button
type="button"
className="modal__close"
onClick={hide}
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<Vehicle
key={showDetails.id}
details={showDetails}
showMore
/>
</div>
</div>
</>,
document.body
)
: null;
};

export default Modal;
93 changes: 93 additions & 0 deletions src/components/Modal/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.modal {

&__overlay {
background-color: #000;
height: 100vh;
left: 0;
opacity: .5;
position: fixed;
top: 0;
width: 100vw;
z-index: 1040;
}

&__wrapper {
height: 100%;
left: 0;
outline: 0;
overflow-x: hidden;
overflow-y: auto;
position: fixed;
top: 0;
width: 100%;
z-index: 1050;
}

&__body {
background: white;
border-radius: 3px;
margin: 1.75rem auto;
max-width: 500px;
position: relative;
z-index: 100;
}

&__close {
border: hidden;
color: #000;
cursor: pointer;
font-size: 2.5rem;
font-weight: 700;
line-height: 1;
opacity: .5;
position: absolute;
right: 0;
z-index: 1;
}
}

.modal__wrapper > .modal__body > .card__vehicle {
border: hidden;
box-shadow: none;
max-width: 600px;
width: 100%;
}

@media only screen and (max-width: 768px) {

.modal__wrapper .modal__body .card {

&__vehicle {
display: flex;
flex-direction: column;
height: 100%;
max-width: 600px;
width: 100%;
}
}

.modal__wrapper .modal__body .card {

&__header {
margin-bottom: .5rem;
padding: 0;
width: 100%;

img {
display: block;
max-height: 300px;
object-fit: contain;
object-position: center;
width: 100%;
}
}

&__body {
width: 100%;

p {
padding-bottom: 1rem;
}
}
}
}
83 changes: 83 additions & 0 deletions src/components/Vehicle/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useContext } from 'react';
import { ModalContext } from '../../contexts/ModalContext';
import './style.scss';

const Vehicle = ({ details, showMore = false }) => {
const {
id: title, price, description, media, meta, modelYear
} = details;

const image = media[0];
const { showModal, setModal, setDetails } = useContext(ModalContext);

const toggle = (value) => {
setDetails(value);
setModal(!showModal);
};

return (
<>
<div className="card__vehicle card--shadow">
<div className="card__header card--image">
<img src={image.url} alt={image.name} />
</div>
<div className="card__body">
<h2>{`Jaguar ${title}`}</h2>
<p>
Model year:
{' '}
<b>{modelYear}</b>
</p>
<p>
From
{' '}
<b>{price}</b>
</p>
<p className="card__description">{description}</p>
{!showMore && (
<button
type="button"
className="card__button"
onClick={() => toggle(details)}
>
<i />
{' '}
Find out more
</button>
)}
</div>
{showMore && (
<div className="card__footer">
<h4>More details</h4>
<p>
CO2 Emissions:
{' '}
<b>
{meta.emissions.value}
{' '}
g/km
</b>
</p>
<p>
Passengers:
{' '}
<b>{meta.passengers}</b>
</p>
<p>
Bodystyle:
{' '}
<b>{meta.bodystyles.join(', ')}</b>
</p>
<p>
Drive Train:
{' '}
<b>{meta.drivetrain.join(', ')}</b>
</p>
</div>
)}
</div>
</>
);
};

export default Vehicle;
Loading