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
2 changes: 2 additions & 0 deletions BeerApp - Senior/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
REACT_APP_API=some_api
REACT_APP_GOOGLE_API_KEY=google_api_key
348 changes: 274 additions & 74 deletions BeerApp - Senior/package-lock.json

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions BeerApp - Senior/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^4.5.8",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.0",
"@mui/material": "^5.13.1",
"@mui/styled-engine-sc": "^5.12.0",
"@react-google-maps/api": "^2.18.1",
"axios": "^1.4.0",
"mui": "^0.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.1"
"react-router-dom": "^6.11.1",
"styled-components": "^5.3.10",
"tss-react": "^4.8.3"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
Expand Down
11 changes: 11 additions & 0 deletions BeerApp - Senior/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,15 @@
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker registration successful with scope: ', registration.scope);
})
.catch(function(err) {
console.log('Service Worker registration failed: ', err);
});
}
</script>
</html>
29 changes: 29 additions & 0 deletions BeerApp - Senior/public/service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* eslint-disable no-restricted-globals */
const CACHE_NAME = 'beer-app-cache';
const urlsToCache = [
'/',
'/index.html',
];

self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});

self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
41 changes: 41 additions & 0 deletions BeerApp - Senior/src/api/localStorageApi/beerLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Beer } from "../../types";


const getSavedBeer = (id: string): Beer | undefined => {
const savedListString = localStorage.getItem('savedList');
if (!savedListString) {
return
}
const savedListParsed = JSON.parse(savedListString);
return savedListParsed.find((beer: Beer) => beer.id === id);
};

const getSavedBeerList = (): Array<Beer> => {
const savedListString = localStorage.getItem('savedList');
if (savedListString) {
const savedListParsed = JSON.parse(savedListString);
return savedListParsed;
}
return [];
};

const saveBeerList = (beerList: Array<Beer>) => {
localStorage.setItem('savedList', JSON.stringify(beerList));
};

const toggleSavedListItem = (id: string, savedList: Array<Beer>, beerList: Array<Beer>) => {
const isSaved = savedList.some((brewery) => brewery.id === id);
let updatedSavedList: Beer[];

if (isSaved) {
updatedSavedList = savedList.filter((brewery) => brewery.id !== id);
} else {
const selectedBrewery = beerList.find((brewery) => brewery.id === id);
updatedSavedList = selectedBrewery ? [...savedList, selectedBrewery] : savedList;
}

return updatedSavedList;
};


export { getSavedBeer, getSavedBeerList, saveBeerList, toggleSavedListItem };
4 changes: 2 additions & 2 deletions BeerApp - Senior/src/types/apiCall.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { TYPE, SORT } from './';

interface ApiParams {
per_page?: number; // Int between 1 and 200. Default is 50.
per_page?: number | string; // Int between 1 and 200. Default is 50.
page?: number;
sort?: SORT; // Not working with by_dist.
sort?: string //name,type:ASC/DESC
by_city?: string;
by_dist?: string; // `${latitude as Number}, ${longitude as Number}`
by_name?: string;
Expand Down
4 changes: 2 additions & 2 deletions BeerApp - Senior/src/types/beer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ interface Beer {
state_province: string;
postal_code: string;
country: string;
longitude: string;
latitude: string;
longitude: number;
latitude: number;
phone: string;
website_url: string;
state: string;
Expand Down
7 changes: 7 additions & 0 deletions BeerApp - Senior/src/views/Beer/Beer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.map-container {
height:400px;
width: 100%;
min-width:400px;
margin-top: 20px;
background-color: grey;
}
104 changes: 87 additions & 17 deletions BeerApp - Senior/src/views/Beer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,98 @@
import { useEffect, useState } from 'react';
import { Beer as IBeer } from '../../types';
import { fetchData } from './utils';
import { fetchBeerData, useMuiStyles } from './utils';
import { useParams } from 'react-router-dom';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import { GoogleMap, useLoadScript } from '@react-google-maps/api';
import { MarkerF } from '@react-google-maps/api'
import "./Beer.css";
import { getSavedBeer, getSavedBeerList, saveBeerList, toggleSavedListItem } from '../../api/localStorageApi/beerLocalStorage';
import { Checkbox } from '@mui/material';


const Beer = () => {
const { id } = useParams();
const [beer, setBeer] = useState<IBeer>();
const { id } = useParams() as { id: string };
const [ beer, setBeer ] = useState<IBeer>();
const [savedList, setSavedList] = useState<Array<IBeer>>([]);
const { classes } = useMuiStyles();

const { isLoaded } = useLoadScript({
googleMapsApiKey: process.env.REACT_APP_GOOGLE_API_KEY || '',
});

useEffect(() => {
setSavedList(getSavedBeerList());
}, []);

useEffect(() => {
if (navigator.onLine) {
fetchBeerData(setBeer, id)
} else {
setBeer(getSavedBeer(id))
}
}, [id]);

// eslint-disable-next-line
useEffect(fetchData.bind(this, setBeer, id), [id]);
const handleToggleFavorite = (id: string) => {
const updatedSavedList = toggleSavedListItem(id, savedList, [beer as IBeer]);
saveBeerList(updatedSavedList);
setSavedList(updatedSavedList);
};

return (
<article>
<section>
<header>
<h1>{beer?.name}</h1>
</header>
<main>
<span>
<b>Type: </b> {beer?.brewery_type}
</span>
</main>
</section>
</article>
<Paper className={classes.root}>
{!beer && (<div>Loading ... </div>)}
{beer && (<div className={classes.cardContent}>
<div>
<Typography variant="subtitle2" component="span">
<Checkbox
checked={savedList.some((fav) => fav.id === id)}
onChange={() => handleToggleFavorite(id)} />
id: {beer?.id}
</Typography>
<Typography variant="h1" component="h1" className={classes.title}>
{beer?.name}
</Typography>
<Typography variant="h2" component="h2" className={classes.subtitle}>
Type: {beer?.brewery_type}
</Typography>
<Typography className={classes.subheading}>Website:</Typography>
<Typography variant="body2" component="p">
{ beer?.website_url
? (<a href={beer?.website_url} target='_blank' rel="noreferrer">{beer?.website_url}</a>)
: ('No website available')
}
</Typography>
<Typography className={classes.subheading}>Phone:</Typography>
<Typography variant="body2" component="p">
{ beer?.phone
? (<a href="tel:{beer?.phone}">{beer?.phone}</a>)
: ('No phone available')
}
</Typography>
<Typography variant="h3" component="h3" className={classes.subheading}>Location:</Typography>
<Typography variant="body2" component="p">
{beer?.street}, {beer?.postal_code}
<br/>{beer?.city}, {beer?.state}
<br/>{beer?.country}
</Typography>
{beer?.latitude && beer?.longitude && (
<div>
{!isLoaded ? (
<h1>Map is Loading...</h1>
) : (
<GoogleMap
mapContainerClassName="map-container"
center={{ lat: beer?.latitude, lng: beer?.longitude }}
zoom={16}>
<MarkerF position={{ lat: beer?.latitude, lng: beer?.longitude }} />
</GoogleMap>
)}
</div>
)}
</div>
</div>)}
</Paper>
);
};

Expand Down
33 changes: 31 additions & 2 deletions BeerApp - Senior/src/views/Beer/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
import { getBeer } from '../../api';
import { Beer } from '../../types';
import handle from '../../utils/error';
import { makeStyles } from 'tss-react/mui';

const fetchData = (setData: (data: Beer) => void, id?: string) => {
const fetchBeerData = (setData: (data: Beer) => void, id?: string) => {
if (!id) return;

(async () => {
try {
const response = await getBeer(id);
console.log(response.data);
const latitude = parseFloat(response.data.latitude) || undefined;
const longitude = parseFloat(response.data.longitude) || undefined;
response.data.latitude = latitude;
response.data.longitude = longitude;
setData(response.data);
} catch (error) {
handle(error);
}
})();
};

export { fetchData };
const useMuiStyles = makeStyles()({
root: {
margin: 'auto',
padding: '20px',
},
title: {
fontWeight: 'bold',
fontSize: '3rem',
marginTop: '10px'
},
subtitle: {
fontSize: '2rem',
marginBottom: '10px'
},
subheading: {
fontSize: '1.75rem',
marginTop: '20px'
},
cardContent: {
display: 'flex'
}
});

export { fetchBeerData, useMuiStyles };
Loading