feat: real user avatars in reviews, conditional product link
This commit is contained in:
@@ -26,8 +26,15 @@ export type PublicReviewFeedItem = {
|
||||
imageUrl: string | null
|
||||
createdAt: string
|
||||
authorDisplay: string
|
||||
productId: string
|
||||
productTitle: string
|
||||
authorAvatar?: string | null
|
||||
authorAvatarType?: string | null
|
||||
authorAvatarStyle?: string | null
|
||||
product: {
|
||||
id: string
|
||||
title: string
|
||||
published: boolean
|
||||
slug: string
|
||||
}
|
||||
}
|
||||
|
||||
export type PublicReviewsLatestResponse = {
|
||||
@@ -48,6 +55,9 @@ export type PublicProductReviewItem = {
|
||||
imageUrl: string | null
|
||||
createdAt: string
|
||||
authorDisplay: string
|
||||
authorAvatar?: string | null
|
||||
authorAvatarType?: string | null
|
||||
authorAvatarStyle?: string | null
|
||||
}
|
||||
|
||||
export type PublicProductReviewsResponse = {
|
||||
|
||||
@@ -19,7 +19,13 @@ function ReviewItem({ rv }: { rv: PublicProductReviewItem }) {
|
||||
<Paper variant="outlined" sx={{ p: 1.5, borderRadius: 2 }}>
|
||||
<Stack spacing={0.75}>
|
||||
<Stack direction="row" spacing={1.5} sx={{ alignItems: 'center' }}>
|
||||
<UserAvatar userId={rv.authorDisplay} avatarUrl={null} avatarType={null} avatarStyle={null} size={32} />
|
||||
<UserAvatar
|
||||
userId={rv.authorDisplay}
|
||||
avatarUrl={rv.authorAvatar}
|
||||
avatarType={rv.authorAvatarType}
|
||||
avatarStyle={rv.authorAvatarStyle}
|
||||
size={32}
|
||||
/>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography sx={{ fontWeight: 700 }}>{rv.authorDisplay}</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -103,9 +103,9 @@ export function ReviewsBlock() {
|
||||
<Stack direction="row" spacing={1.5} sx={{ minWidth: { sm: 200 }, alignItems: 'center' }}>
|
||||
<UserAvatar
|
||||
userId={r.authorDisplay}
|
||||
avatarUrl={null}
|
||||
avatarType={null}
|
||||
avatarStyle={null}
|
||||
avatarUrl={r.authorAvatar}
|
||||
avatarType={r.authorAvatarType}
|
||||
avatarStyle={r.authorAvatarStyle}
|
||||
size={40}
|
||||
/>
|
||||
<Box>
|
||||
@@ -122,20 +122,26 @@ export function ReviewsBlock() {
|
||||
{formatReviewDate(r.createdAt)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Typography
|
||||
variant="caption"
|
||||
component={RouterLink}
|
||||
to={`/products/${r.productId}`}
|
||||
sx={{
|
||||
display: 'block',
|
||||
mt: 0.25,
|
||||
color: 'primary.main',
|
||||
textDecoration: 'none',
|
||||
'&:hover': { textDecoration: 'underline' },
|
||||
}}
|
||||
>
|
||||
{r.productTitle}
|
||||
</Typography>
|
||||
{r.product.published ? (
|
||||
<Typography
|
||||
variant="caption"
|
||||
component={RouterLink}
|
||||
to={`/products/${r.product.slug || r.product.id}`}
|
||||
sx={{
|
||||
display: 'block',
|
||||
mt: 0.25,
|
||||
color: 'primary.main',
|
||||
textDecoration: 'none',
|
||||
'&:hover': { textDecoration: 'underline' },
|
||||
}}
|
||||
>
|
||||
{r.product.title}
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.25 }}>
|
||||
{r.product.title}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ export async function registerPublicReviewRoutes(fastify) {
|
||||
const rows = await prisma.review.findMany({
|
||||
where: { status: 'approved', product: { published: true } },
|
||||
include: {
|
||||
user: { select: { email: true, displayName: true } },
|
||||
product: { select: { id: true, title: true } },
|
||||
user: { select: { email: true, displayName: true, avatar: true, avatarType: true, avatarStyle: true } },
|
||||
product: { select: { id: true, title: true, published: true, slug: true } },
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take,
|
||||
@@ -54,8 +54,15 @@ export async function registerPublicReviewRoutes(fastify) {
|
||||
imageUrl: r.imageUrl,
|
||||
createdAt: r.createdAt,
|
||||
authorDisplay: publicReviewAuthorDisplay(r.user),
|
||||
productId: r.productId,
|
||||
productTitle: r.product?.title ?? '',
|
||||
authorAvatar: r.user?.avatar ?? null,
|
||||
authorAvatarType: r.user?.avatarType ?? null,
|
||||
authorAvatarStyle: r.user?.avatarStyle ?? null,
|
||||
product: {
|
||||
id: r.product?.id ?? r.productId,
|
||||
title: r.product?.title ?? '',
|
||||
published: r.product?.published ?? false,
|
||||
slug: r.product?.slug ?? '',
|
||||
},
|
||||
}))
|
||||
|
||||
return { items }
|
||||
@@ -80,7 +87,7 @@ export async function registerPublicReviewRoutes(fastify) {
|
||||
const total = await prisma.review.count({ where })
|
||||
const rawItems = await prisma.review.findMany({
|
||||
where,
|
||||
include: { user: { select: { email: true, displayName: true } } },
|
||||
include: { user: { select: { email: true, displayName: true, avatar: true, avatarType: true, avatarStyle: true } } },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
@@ -93,6 +100,9 @@ export async function registerPublicReviewRoutes(fastify) {
|
||||
imageUrl: r.imageUrl,
|
||||
createdAt: r.createdAt,
|
||||
authorDisplay: publicReviewAuthorDisplay(r.user),
|
||||
authorAvatar: r.user?.avatar ?? null,
|
||||
authorAvatarType: r.user?.avatarType ?? null,
|
||||
authorAvatarStyle: r.user?.avatarStyle ?? null,
|
||||
}))
|
||||
|
||||
return { items, total, page, pageSize }
|
||||
|
||||
Reference in New Issue
Block a user