tsx
53 lines
1.79 KB
| 1 | import { |
| 2 | CardTitle, |
| 3 | CardDescription, |
| 4 | CardHeader, |
| 5 | CardContent, |
| 6 | Card, |
| 7 | } from "@/components/ui/card"; |
| 8 | import { Product } from "@/lib/types"; |
| 9 | import { summarizeReviews } from "@/lib/ai-summary"; |
| 10 | import { FiveStarRating } from "./five-star-rating"; |
| 11 | |
| 12 | export async function AIReviewSummary({ product }: { product: Product }) { |
| 13 | const summary = await summarizeReviews(product); |
| 14 | const averageRating = |
| 15 | product.reviews.reduce((acc, review) => acc + review.stars, 0) / |
| 16 | product.reviews.length; |
| 17 | return ( |
| 18 | <Card className="w-full max-w-prose p-10 grid gap-10"> |
| 19 | <CardHeader className="items-center space-y-0 gap-4 p-0"> |
| 20 | <div className="grid gap-1 text-center"> |
| 21 | <CardTitle className="text-lg">Review Summary</CardTitle> |
| 22 | <CardDescription className="text-xs"> |
| 23 | Based on {product.reviews.length} customer ratings |
| 24 | </CardDescription> |
| 25 | </div> |
| 26 | <div className="bg-gray-100 px-3 rounded-full flex items-center py-2 dark:bg-gray-800"> |
| 27 | <FiveStarRating rating={Math.round(averageRating)} /> |
| 28 | <span className="text-sm ml-4 text-gray-500 dark:text-gray-400"> |
| 29 | {numberWithOneDecimal(averageRating)} out of 5 |
| 30 | </span> |
| 31 | <a |
| 32 | href="https://maps.app.goo.gl/f4irVqGC9KGHzRDP9" |
| 33 | target="_blank" |
| 34 | rel="noopener noreferrer" |
| 35 | className="ml-6 underline text-xs text-blue-600" |
| 36 | > |
| 37 | Google page |
| 38 | </a> |
| 39 | </div> |
| 40 | </CardHeader> |
| 41 | <CardContent className="p-0 grid gap-4"> |
| 42 | <p className="text-sm leading-loose text-gray-500 dark:text-gray-400"> |
| 43 | {summary} |
| 44 | </p> |
| 45 | </CardContent> |
| 46 | </Card> |
| 47 | ); |
| 48 | } |
| 49 | |
| 50 | function numberWithOneDecimal(num: number) { |
| 51 | if (num === Math.round(num)) return num; |
| 52 | return Math.round(num * 10) / 10; |
| 53 | } |