diff --git a/web/frontend/app/features/breweries/components/BeerListCard.tsx b/web/frontend/app/features/breweries/components/BeerListCard.tsx new file mode 100644 index 00000000..70ea4cdf --- /dev/null +++ b/web/frontend/app/features/breweries/components/BeerListCard.tsx @@ -0,0 +1,42 @@ +import { Link } from 'react-router'; +import StarRating from './StarRating'; +import type { FillerBeer } from '../utils/filler-brewery-detail'; + +interface BeerListCardProps { + beers: FillerBeer[]; +} + +const BeerListCard = ({ beers }: BeerListCardProps) => ( +
+
+
+

Beers ({beers.length})

+ + View all beers + +
+
+ {beers.map((beer) => ( +
+
+ {beer.name} + {beer.description} +
+ + {beer.style} + + + {beer.abv.toFixed(1)}% ABV + + +
+ ))} +
+
+
+); + +export default BeerListCard; diff --git a/web/frontend/app/features/breweries/components/BreweryHeaderCard.tsx b/web/frontend/app/features/breweries/components/BreweryHeaderCard.tsx new file mode 100644 index 00000000..0bdc115c --- /dev/null +++ b/web/frontend/app/features/breweries/components/BreweryHeaderCard.tsx @@ -0,0 +1,70 @@ +import { Heart, HeartSolid, MapPin } from 'iconoir-react'; +import StarRating from './StarRating'; +import { formatBreweryAddress } from '../utils/format-address'; +import type { Brewery } from '../breweries.server'; + +interface BreweryHeaderCardProps { + brewery: Brewery; + foundedYear: number; + liked: boolean; + likeCount: number; + avgRating: number; + ratingsCount: number; + onToggleLike: () => void; +} + +const BreweryHeaderCard = ({ + brewery, + foundedYear, + liked, + likeCount, + avgRating, + ratingsCount, + onToggleLike, +}: BreweryHeaderCardProps) => ( +
+
+
+
+ + Brewery + + + Est. {foundedYear} + +
+

{brewery.breweryName}

+ {brewery.location && ( +

+

+ )} +
+
+ +
+ + {avgRating.toFixed(1)} + ({ratingsCount} ratings) +
+
+

+ {brewery.description} +

+
+
+); + +export default BreweryHeaderCard; diff --git a/web/frontend/app/features/breweries/components/CommentItem.tsx b/web/frontend/app/features/breweries/components/CommentItem.tsx new file mode 100644 index 00000000..ed3bb20f --- /dev/null +++ b/web/frontend/app/features/breweries/components/CommentItem.tsx @@ -0,0 +1,46 @@ +import { Heart, HeartSolid } from 'iconoir-react'; +import StarRating from './StarRating'; +import type { FillerComment } from '../utils/filler-brewery-detail'; + +interface CommentItemProps { + comment: FillerComment; + onToggleLike: (id: string) => void; +} + +const CommentItem = ({ comment, onToggleLike }: CommentItemProps) => { + const likeCount = comment.likes + (comment.liked ? 1 : 0); + + return ( +
+
+
+ {comment.initials} +
+
+
+
+ {comment.user} + + {comment.time} +
+

{comment.text}

+ +
+
+ ); +}; + +export default CommentItem; diff --git a/web/frontend/app/features/breweries/components/CommentsCard.tsx b/web/frontend/app/features/breweries/components/CommentsCard.tsx new file mode 100644 index 00000000..78ab8dc6 --- /dev/null +++ b/web/frontend/app/features/breweries/components/CommentsCard.tsx @@ -0,0 +1,79 @@ +import { useState } from 'react'; +import CommentItem from './CommentItem'; +import type { FillerComment } from '../utils/filler-brewery-detail'; + +interface CommentsCardProps { + comments: FillerComment[]; + loggedIn: boolean; + currentUserInitials: string; + onAddComment: (text: string) => void; + onToggleCommentLike: (id: string) => void; +} + +const CommentsCard = ({ + comments, + loggedIn, + currentUserInitials, + onAddComment, + onToggleCommentLike, +}: CommentsCardProps) => { + const [commentText, setCommentText] = useState(''); + + const handleSubmit = () => { + const text = commentText.trim(); + if (!text) return; + onAddComment(text); + setCommentText(''); + }; + + return ( +
+
+

Comments ({comments.length})

+ + {loggedIn ? ( +
+
+
+ {currentUserInitials} +
+
+
+