-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FeaturePanel: add Food hygiene rating scheme (#179)
- Loading branch information
Showing
5 changed files
with
170 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
src/components/FeaturePanel/renderers/FoodHygieneRatingScheme.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { Typography } from '@material-ui/core'; | ||
import { Restaurant } from '@material-ui/icons'; | ||
import { getEstablishmentRatingValue } from '../../../services/fhrsApi'; | ||
|
||
interface StarRatingProps { | ||
stars: number; | ||
maxStars: number; | ||
} | ||
|
||
const StarRating = ({ stars, maxStars }: StarRatingProps) => { | ||
const starArray = new Array(maxStars).fill(0); | ||
return ( | ||
<div> | ||
{starArray.map((_, i) => ( | ||
<span>{i < stars ? '★' : '☆'}</span> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
const useLoadingState = () => { | ||
const [rating, setRating] = useState<number>(); | ||
const [error, setError] = useState<string>(); | ||
const [loading, setLoading] = useState(true); | ||
|
||
const finishRating = (payload) => { | ||
setLoading(false); | ||
setRating(payload); | ||
}; | ||
|
||
const startRating = () => { | ||
setLoading(true); | ||
setRating(undefined); | ||
setError(undefined); | ||
}; | ||
|
||
const failRating = () => { | ||
setError('Could not load rating'); | ||
setLoading(false); | ||
}; | ||
|
||
return { rating, error, loading, startRating, finishRating, failRating }; | ||
}; | ||
|
||
export const FoodHygieneRatingSchemeRenderer = ({ v }) => { | ||
const { rating, error, loading, startRating, finishRating, failRating } = | ||
useLoadingState(); | ||
|
||
useEffect(() => { | ||
const loadData = async () => { | ||
startRating(); | ||
const ratingValue = await getEstablishmentRatingValue(v); | ||
if (Number.isNaN(rating)) { | ||
failRating(); | ||
} | ||
finishRating(ratingValue); | ||
}; | ||
|
||
loadData(); | ||
}, []); | ||
|
||
const linkStyle: React.CSSProperties = { | ||
display: 'flex', | ||
alignItems: 'center', | ||
gap: '0.5rem', | ||
}; | ||
const pStyle: React.CSSProperties = { | ||
marginBlock: '0', | ||
}; | ||
|
||
return ( | ||
<> | ||
{loading ? ( | ||
<> | ||
<span className="dotloader" /> | ||
<span className="dotloader" /> | ||
<span className="dotloader" /> | ||
</> | ||
) : ( | ||
<> | ||
<Restaurant fontSize="small" /> | ||
{Number.isNaN(rating) || error ? ( | ||
<Typography color="error">No rating available</Typography> | ||
) : ( | ||
<> | ||
<a | ||
href={`https://ratings.food.gov.uk/business/${v}`} | ||
title="Food Hygiene Rating Scheme" | ||
style={linkStyle} | ||
> | ||
<p style={pStyle}>FHRS</p> | ||
<StarRating stars={rating} maxStars={5} /> | ||
</a> | ||
</> | ||
)} | ||
</> | ||
)} | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import * as fetchModule from '../fetch'; | ||
import { getEstablishmentRatingValue } from '../fhrsApi'; | ||
|
||
describe('fetchRating', () => { | ||
it('should return a rating between 0 and 5', async () => { | ||
const fetchJsonMock = jest | ||
.spyOn(fetchModule, 'fetchJson') | ||
.mockResolvedValue({ | ||
FHRSID: 423824, | ||
ChangesByServerID: 0, | ||
LocalAuthorityBusinessID: '13359', | ||
BusinessName: 'Caffe Nero', | ||
BusinessType: 'Restaurant/Cafe/Canteen', | ||
BusinessTypeID: 1, | ||
AddressLine1: '', | ||
AddressLine2: '30 Monmouth Street', | ||
AddressLine3: '', | ||
AddressLine4: 'London', | ||
PostCode: 'WC2H 9HA', | ||
Phone: '', | ||
RatingValue: '5', | ||
RatingKey: 'fhrs_5_en-gb', | ||
RatingDate: '2019-09-11T00:00:00', | ||
LocalAuthorityCode: '506', | ||
LocalAuthorityName: 'Camden', | ||
LocalAuthorityWebSite: 'http://www.camden.gov.uk', | ||
LocalAuthorityEmailAddress: '[email protected]', | ||
scores: { | ||
Hygiene: 0, | ||
Structural: 0, | ||
ConfidenceInManagement: 0, | ||
}, | ||
SchemeType: 'FHRS', | ||
geocode: { | ||
longitude: '-0.1272279', | ||
latitude: '51.5136148', | ||
}, | ||
RightToReply: '', | ||
Distance: null, | ||
NewRatingPending: false, | ||
}); | ||
|
||
const rating = await getEstablishmentRatingValue(269382); | ||
expect(rating).toBeLessThanOrEqual(5); | ||
fetchJsonMock.mockRestore(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { fetchJson } from './fetch'; | ||
|
||
function fetchEstablishmentData(id: number) { | ||
return fetchJson(`https://api.ratings.food.gov.uk/Establishments/${id}`, { | ||
headers: { | ||
'x-api-version': '2', | ||
}, | ||
}); | ||
} | ||
|
||
export async function getEstablishmentRatingValue(id: number) { | ||
const allData = await fetchEstablishmentData(id).catch(() => null); | ||
const ratingString = allData?.RatingValue; | ||
const ratingValue = parseInt(ratingString, 10); | ||
return ratingValue; | ||
} |