import type { ReactNode } from "react"; /** A photo attached to a review. */ export interface ReviewMedia { /** Stable React key for the photo. */ id: string; /** Image URL, shown as a lazy-loaded 72px thumbnail. */ src: string; /** Alt text; falls back to `labels.photoAlt` with the author's name. */ alt?: string; } /** One customer review. */ export interface ReviewItem { /** Stable key for the review; passed to `onHelpful` and used for expand and helpful state. */ id: string; /** Reviewer name shown in the byline and in the fallback photo alt text. */ author: string; /** Reviewer's city, shown after the author name when given. */ city?: string; /** Whole stars, 1 to 5. */ rating: number; /** ISO date such as "2026-09-21"; formatted per `locale`, and shown as given when it is not a valid date. */ date: string; /** Heading beside the stars; omitted when empty. */ title?: string; /** Review text; clamped to four lines when longer than `clampChars`. */ body: string; /** Adds the "Verified purchase" marker. */ verified?: boolean; /** Helpful votes so far. */ helpful?: number; /** Variant the reviewer bought, e.g. "M". */ purchasedSize?: string; /** Photos shown as thumbnails under the body. */ media?: ReviewMedia[]; } /** Every string the list renders; override all of them for another language. */ export interface ReviewListLabels { /** Marker text shown when a review is `verified`. */ verified: string; /** Button name, given the vote count. */ helpful: (count: number) => string; /** Toggle text on a clamped body. */ readMore: string; /** Toggle text on an expanded body. */ readLess: string; /** Load-more button text. */ loadMore: string; /** Load-more button text while `isLoadingMore`. */ loadingMore: string; /** Heading of the default empty state. */ emptyTitle: string; /** Supporting text of the default empty state. */ emptyBody: string; /** Detail line, given the size the reviewer bought. */ purchasedSize: (size: string) => string; /** Screen-reader text while skeleton rows show. */ loadingReviews?: string; /** Polite announcement when a page is appended, given how many reviews arrived. */ moreLoaded?: (count: number) => string; /** Fallback alt text for a photo without one, given the reviewer's name. */ photoAlt?: (author: string) => string; } /** Customer reviews with verified marker, helpful votes, clamped long bodies, a sort slot and load-more paging. */ export interface ReviewListProps { /** Reviews to render in order; an empty list shows the empty state. */ reviews: ReviewItem[]; /** Fires with the review id when "Helpful" is pressed; the button then shows as pressed and the count rises by one. */ onHelpful?: (reviewId: string) => void; /** Bodies longer than this many characters are clamped to four lines behind a "Read more" toggle. */ clampChars?: number; /** Rendered above the list, typically a `Select` for sorting. */ sortSlot?: ReactNode; /** Shows the "Load more" button. */ hasMore?: boolean; /** Fires when "Load more" is pressed; the parent appends the next page to `reviews`. */ onLoadMore?: () => void; /** Shows skeleton rows in place of the reviews. */ isLoading?: boolean; /** Disables "Load more" and shows `labels.loadingMore` while the next page loads. */ isLoadingMore?: boolean; /** Replaces the default empty state. */ emptyState?: ReactNode; /** Locale for review dates; defaults to en-IN, and an invalid locale falls back to it. */ locale?: string; /** Partial overrides of the default English strings. */ labels?: Partial; /** Test id on the root section; each review row also carries `review-`. */ "data-testid"?: string; }