'use client';
import { Star } from 'lucide-react';
import { api } from '@/lib/trpc';
import { Button, EmptyState } from '@/components/ui';
import { cn, formatRelativeTime } from '@/lib/utils';
/**
* Five stars, filled to the rating.
*
* The number goes in the accessible name rather than being inferred from a row
* of glyphs — §8, meaning is never carried by shape alone. The stars themselves
* are decorative once the label says "4 out of 5".
*/
function Stars({ rating, className }: { rating: number; className?: string }) {
return (
{[1, 2, 3, 4, 5].map((n) => (
))}
);
}
/**
* What people wrote about this pro.
*
* A page, never the whole history: `ratingCount` in the header counts every
* rating this pro has ever had, and a profile with sixty of them would push the
* hire button somewhere nobody scrolls. The heading says which it is showing so
* the two numbers cannot be read as a contradiction.
*
* Only published reviews exist as far as this is concerned — `pro.reviews`
* enforces that server-side, because the publication gate is what stops a pro
* retaliating against a bad review before it is visible.
*/
export function ReviewList({ proId, ratingCount }: { proId: string; ratingCount: number }) {
const reviews = api.pro.reviews.useInfiniteQuery(
{ proId },
{ getNextPageParam: (last) => last.nextCursor, staleTime: 60_000, retry: false },
);
const rows = reviews.data?.pages.flatMap((page) => page.reviews) ?? [];
if (reviews.isLoading) {
return (
{/* §6.11 — three is enough to say "loading"; twenty is a lie about what
is coming. */}
{[0, 1, 2].map((n) => (
))}
);
}
if (rows.length === 0) {
return (
0
? 'This pro has been rated, but nobody has left written feedback that is public yet.'
: 'Nobody has reviewed this pro yet. Reviews appear once a booking is finished.'
}
/>
);
}
return (