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
14 changes: 14 additions & 0 deletions BeerApp - Senior/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
moduleDirectories: ['node_modules', 'src'],
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts', 'src/**/*.tsx'],
coverageReporters: ['json-summary', 'text', 'lcov'],
extensionsToTreatAsEsm: ['.ts'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};
1,023 changes: 778 additions & 245 deletions BeerApp - Senior/package-lock.json

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions BeerApp - Senior/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,37 @@
"@fontsource/roboto": "^4.5.8",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.0",
"@popperjs/core": "^2.11.8",
"axios": "^1.4.0",
"leaflet": "^1.9.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-leaflet": "^4.2.1",
"react-router-dom": "^6.11.1"
},
"devDependencies": {
"@babel/preset-typescript": "^7.23.3",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/leaflet": "^1.9.8",
"@types/node": "^16.18.28",
"@types/react": "^18.2.6",
"@types/react-dom": "^18.2.4",
"jest": "^27.4.7",
"react-scripts": "5.0.1",
"react-test-renderer": "^18.0.0",
"ts-jest": "^27.0.7",
"typescript": "^4.9.5",
"typescript-plugin-css-modules": "^5.0.1"
"typescript-plugin-css-modules": "^5.0.1",
"workbox-webpack-plugin": "^7.0.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\""
},
"eslintConfig": {
"extends": [
Expand Down
37 changes: 37 additions & 0 deletions BeerApp - Senior/public/service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// public/service-worker.js

self.addEventListener('install', (event) => {
const urlsToCache = [
'/',
'/index.html',
// Add other URLs you want to cache...
];

event.waitUntil(
caches.open('my-cache').then((cache) => {
return cache.addAll(urlsToCache);
})
);
});

self.addEventListener('fetch', (event) => {
event.respondWith(
// Try to fetch the request from the network
fetch(event.request).then((response) => {
// If the fetch is successful, clone the response and cache it
if (response.ok) {
const clone = response.clone();
caches.open('my-cache').then((cache) => {
cache.put(event.request, clone);
});
}
return response;
}).catch(() => {
// If the fetch fails (e.g., when offline), try to respond with the cached version
return caches.match(event.request).then((cachedResponse) => {
return cachedResponse || new Response('', { status: 404, statusText: 'Not Found' });
});
})
);
});

22 changes: 22 additions & 0 deletions BeerApp - Senior/src/components/Map/Map.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { useRef } from "react";
import { MapContainer, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";

const Map = ({lat, lang}) => {
const mapRef = useRef(null);
const latitude = lat;
const longitude = lang;

return (
// Make sure you set the height and width of the map container otherwise the map won't show
<MapContainer center={[latitude, longitude]} zoom={13} ref={mapRef} style={{height: "100vh", width: "100vw"}}>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{/* Additional map layers or components can be added here */}
</MapContainer>
);
};

export default Map;
15 changes: 9 additions & 6 deletions BeerApp - Senior/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@emotion/react';
import { theme } from './styles/theme';
import './styles/global.css';
import { registerServiceWorker } from './registerServiceWorker';

registerServiceWorker();

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<CssBaseline />
<ThemeProvider theme={theme}>
<Router />
</ThemeProvider>
</React.StrictMode>
<React.StrictMode>
<CssBaseline />
<ThemeProvider theme={theme}>
<Router />
</ThemeProvider>
</React.StrictMode>
);
15 changes: 15 additions & 0 deletions BeerApp - Senior/src/registerServiceWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// registerServiceWorker.js or registerServiceWorker.ts

export const registerServiceWorker = () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js')
.then((registration) => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch((error) => {
console.error('Service Worker registration failed:', error);
});
}
};

1 change: 1 addition & 0 deletions BeerApp - Senior/src/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
14 changes: 14 additions & 0 deletions BeerApp - Senior/src/utils/favoritesUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const saveAsFavourite = (id: string, setFavourite: React.Dispatch<React.SetStateAction<string[]>>) => {
const favouriteList = JSON.parse(localStorage.getItem('favouriteList') || '[]');
if (favouriteList.indexOf(id) === -1) {
favouriteList.push(id);
localStorage.setItem('favouriteList', JSON.stringify(favouriteList));
setFavourite(favouriteList);
} else {
favouriteList.splice(favouriteList.indexOf(id), 1);
localStorage.setItem('favouriteList', JSON.stringify(favouriteList));
setFavourite(favouriteList);
}
};

export default saveAsFavourite;
32 changes: 32 additions & 0 deletions BeerApp - Senior/src/views/Beer/Map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useRef } from "react";
import { MapContainer, Marker, Popup, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";

interface MapProps {
lat: number;
lang: number;
}

const Map: React.FC<MapProps> = ({ lat, lang }) => {
const mapRef = useRef(null);
const latitude = lat;
const longitude = lang;

return (
// Make sure you set the height and width of the map container otherwise the map won't show
<MapContainer center={[latitude, longitude]} zoom={15} ref={mapRef} style={{height: "70vh", width: "40vw"}}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
{/* Additional map layers or components can be added here */}
<Marker position={[latitude, longitude]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};

export default Map;
15 changes: 15 additions & 0 deletions BeerApp - Senior/src/views/Beer/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { render, screen } from '@testing-library/react';
import Beer from './index';

describe('Beer', () => {

test('renders Beer component', () => {
render(<Beer />);
expect(screen.getByText('Beer Details')).toBeInTheDocument();
});

test('checks the type of Beer component', () => {
render(<Beer />);
expect(typeof Beer).toBe('function');
});
});
91 changes: 73 additions & 18 deletions BeerApp - Senior/src/views/Beer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,83 @@ import { useEffect, useState } from 'react';
import { Beer as IBeer } from '../../types';
import { fetchData } from './utils';
import { useParams } from 'react-router-dom';
import { Typography, IconButton } from '@mui/material';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import Map from './Map';
import saveAsFavourite from '../../utils/favoritesUtils';
import FavoriteIcon from '@mui/icons-material/Favorite';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';

const Beer = () => {
const { id } = useParams();
const [beer, setBeer] = useState<IBeer>();
const { id } = useParams();
const [beer, setBeer] = useState<IBeer>();
const [favourite, setFavourite] = useState<Array<string>>([]);

// eslint-disable-next-line
useEffect(fetchData.bind(this, setBeer, id), [id]);
// eslint-disable-next-line
useEffect(fetchData.bind(this, setBeer, id), [id]);

return (
<article>
<section>
<header>
<h1>{beer?.name}</h1>
</header>
<main>
<span>
<b>Type: </b> {beer?.brewery_type}
</span>
</main>
</section>
</article>
);
useEffect(() => {
let data = JSON.parse(localStorage.getItem('favouriteList') || '[]');
setFavourite(data);
}, [id]);

const saveFavourite = (id: string) => {
saveAsFavourite(id, setFavourite);
};

return (
<Box sx={{ flexGrow: 1, padding: 3 }}>
<h2>Beer Details</h2>
<Grid container spacing={3}>
<Grid item xs={12} md={5}>
<article>
<section>
<Typography variant="h4" gutterBottom>
{beer?.name} <IconButton onClick={saveFavourite.bind(this, beer?.id ?? "")} color="primary" size="large">
{favourite.includes(beer?.id ?? '') ? <FavoriteIcon /> : <FavoriteBorderIcon />}
</IconButton>
</Typography>
<Typography variant="body1">
<b>Type:</b> {beer?.brewery_type}
</Typography>
<Typography variant="body1">
<b>Street:</b> {beer?.street}
</Typography>
<Typography variant="body1">
<b>City:</b> {beer?.city}
</Typography>
<Typography variant="body1">
<b>State:</b> {beer?.state}
</Typography>
<Typography variant="body1">
<b>Postal Code:</b> {beer?.postal_code}
</Typography>
<Typography variant="body1">
<b>Country:</b> {beer?.country}
</Typography>
<Typography variant="body1">
<b>Longitude:</b> {beer?.longitude}
</Typography>
<Typography variant="body1">
<b>Latitude:</b> {beer?.latitude}
</Typography>
<Typography variant="body1">
<b>Phone:</b> {beer?.phone}
</Typography>
<Typography variant="body1">
<b>Website:</b> {beer?.website_url}
</Typography>
</section>
</article>
</Grid>
<Grid item xs={12} md={7}>
{beer?.latitude && beer?.longitude && <Map lat={Number(beer.latitude)} lang={Number(beer.longitude)} />}
</Grid>
</Grid>
</Box>

);
};

export default Beer;
12 changes: 12 additions & 0 deletions BeerApp - Senior/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// webpack.config.js or webpack.config.prod.js

const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

module.exports = {
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
}),
],
};