Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 22x 112x 22x 113x 113x 22x 9x | import { Stack } from "@mui/material";
import GiveStarRating from "@shared/StarRating/GiveStarRating";
import GiveText from "@shared/Text/GiveText";
import { EventReviewStats } from "./review.types";
type Props = {
stats: EventReviewStats;
};
/**
* A missing or null average must not take the whole tab down with it: the stats
* read can fail, and `EventReviewStats` is only as reliable as that response —
* so an unusable value reads as 0.00 rather than throwing out of render.
*/
export const formatAverage = (value?: number | null) =>
(Number.isFinite(value) ? (value as number) : 0).toFixed(2);
export const reviewCountLabel = (total?: number | null) => {
const count = Number.isFinite(total) ? (total as number) : 0;
return `${count} ${count === 1 ? "review" : "reviews"}`;
};
/**
* The event's score as the side panel shows it: stars, average, count
* (frame 7878-57940). The Reviews tab's sidebar arranges the same numbers
* differently and adds the 1-5 distribution, so it draws its own.
*
* Read from its own endpoint, so it always describes the whole event however
* the list beneath it is filtered.
*/
const EventReviewSummary = ({ stats }: Props) => {
return (
<Stack gap="16px" data-testid="event-review-summary">
<Stack direction="row" gap="12px" alignItems="center" flexWrap="wrap">
<GiveStarRating value={stats.averageRating} />
<GiveText variant="bodyM" color="primary">
{formatAverage(stats.averageRating)}
</GiveText>
<GiveText variant="bodyS" color="secondary">
{reviewCountLabel(stats.total)}
</GiveText>
</Stack>
</Stack>
);
};
export default EventReviewSummary;
|