Add reviews to the website
This commit is contained in:
50
astro/src/components/web/Reviews.astro
Normal file
50
astro/src/components/web/Reviews.astro
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
import StarRating from './subcomponents/StarRating.astro';
|
||||
|
||||
interface Props {
|
||||
reviews: ReviewListComponent;
|
||||
}
|
||||
|
||||
const reviews = Astro.props.reviews;
|
||||
|
||||
let totalStars: number = 0;
|
||||
const totalReviews: number = reviews.reviews.length;
|
||||
|
||||
reviews.reviews.forEach((review) => {
|
||||
totalStars = totalStars + review.stars;
|
||||
});
|
||||
|
||||
const averageStars = Math.round((totalStars / totalReviews) * 10) / 10;
|
||||
const reviewsToShow = reviews.reviews.slice(0, 5);
|
||||
---
|
||||
|
||||
<div class="flex flex-row py-12 px-12 lg:container mx-auto gap-y-8 gap-x-18 w-full">
|
||||
<div class="flex flex-col gap-5 min-w-[32.5%]">
|
||||
<div class="flex flex-col">
|
||||
<h2 class="text-3xl font-bold">{reviews.title}</h2>
|
||||
<div>{reviews.text}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5 text-lg">
|
||||
<StarRating size="big" stars={averageStars} />
|
||||
<p class="italic">{averageStars}</span> stars out of {totalReviews} {totalReviews === 1 ? "review" : "reviews"}.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-6.5">
|
||||
{ reviewsToShow.map((review) => (
|
||||
<div class="flex flex-col justify-center gap-3 bg-neutral-50 py-4 px-5.5 rounded-2xl shadow-sm">
|
||||
<div class="flex flex-col justify-center gap-[5px]">
|
||||
<h4 class="text-2xl font-semibold">{review.name}</h4>
|
||||
<div>
|
||||
<StarRating size="small" stars={review.stars} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{ review.review }
|
||||
</div>
|
||||
</div>
|
||||
)) }
|
||||
</div>
|
||||
</div>
|
||||
71
astro/src/components/web/subcomponents/StarRating.astro
Normal file
71
astro/src/components/web/subcomponents/StarRating.astro
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
interface Props {
|
||||
stars: number;
|
||||
size: "big" | "small";
|
||||
}
|
||||
|
||||
function roundToCustomHalf(value: number) {
|
||||
const whole = Math.floor(value);
|
||||
const decimal = value - whole;
|
||||
|
||||
if (decimal < 0.25) return whole;
|
||||
if (decimal < 0.75) return whole + 0.5;
|
||||
return whole + 1;
|
||||
}
|
||||
|
||||
const stars = roundToCustomHalf(Astro.props.stars);
|
||||
const totalStars = 5;
|
||||
---
|
||||
|
||||
<div class="flex flex-row gap-[4.25px]">
|
||||
{Array.from({ length: totalStars }).map((_, i) => {
|
||||
const starValue = i + 1;
|
||||
let type = "empty";
|
||||
|
||||
if (stars >= starValue) {
|
||||
type = "full";
|
||||
} else if (stars >= starValue - 0.5) {
|
||||
type = "half";
|
||||
}
|
||||
|
||||
return (
|
||||
<svg width={Astro.props.size === "big" ? 32 : 20} height={Astro.props.size === "big" ? 32 : 20} viewBox="3 0 24 24">
|
||||
{type === "full" && (
|
||||
<path
|
||||
fill="gold"
|
||||
d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22
|
||||
12 18.56 5.82 22 7 14.14 2 9.27
|
||||
8.91 8.26 12 2z"
|
||||
/>
|
||||
)}
|
||||
|
||||
{type === "half" && (
|
||||
<>
|
||||
<defs>
|
||||
<linearGradient id={`half-${i}`}>
|
||||
<stop offset="50%" stop-color="gold" />
|
||||
<stop offset="50%" stop-color="lightgray" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
fill={`url(#half-${i})`}
|
||||
d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22
|
||||
12 18.56 5.82 22 7 14.14 2 9.27
|
||||
8.91 8.26 12 2z"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{type === "empty" && (
|
||||
<path
|
||||
fill="lightgray"
|
||||
d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22
|
||||
12 18.56 5.82 22 7 14.14 2 9.27
|
||||
8.91 8.26 12 2z"
|
||||
/>
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import TextWithImage from '../web/TextWithImage.astro';
|
||||
import UpcomingEvents from '../web/UpcomingEvents.astro';
|
||||
import WallOfText from '../web/WallOfText.astro';
|
||||
import EquipmentTable from '../web/EquipmentTable.astro';
|
||||
import Reviews from '../web/Reviews.astro';
|
||||
|
||||
interface Props {
|
||||
webpage: WebpageComponent[];
|
||||
@@ -24,6 +25,7 @@ console.log(Astro.props.webpage);
|
||||
{ component.component === "UpcomingEvents" && <UpcomingEvents upcomingEvents={component} /> }
|
||||
{ component.component === "FrequentlyAskedQuestions" && <FrequentlyAskedQuestions faq={component} /> }
|
||||
{ component.component === "EquipmentTable" && <EquipmentTable equipment={component} /> }
|
||||
{ component.component === "Reviews" && <Reviews reviews={component} /> }
|
||||
</Fragment>
|
||||
)) }
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user