Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to aggregate similar products to verified reviews #634

16 changes: 14 additions & 2 deletions verified-reviews/loaders/productDetailsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
getProductId,
PaginationOptions,
} from "../utils/client.ts";
export type Props = PaginationOptions;

export type Props = PaginationOptions & {
aggregateSimilarProducts?: boolean;
};

/**
* @title Opiniões verificadas - Full Review for Product (Ratings and Reviews)
Expand All @@ -27,8 +30,17 @@ export default function productDetailsPage(
}

const productId = getProductId(productDetailsPage.product);
let productsToGetReviews = [productId];

if (config.aggregateSimilarProducts) {
productsToGetReviews = [
productId,
...productDetailsPage.product.isSimilarTo?.map(getProductId) ?? [],
];
}

const fullReview = await client.fullReview({
productId,
productsIds: productsToGetReviews,
count: config?.count,
offset: config?.offset,
order: config?.order,
Expand Down
33 changes: 33 additions & 0 deletions verified-reviews/loaders/productReviews.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { AppContext } from "../mod.ts";
import { Review } from "../../commerce/types.ts";
import { createClient, PaginationOptions } from "../utils/client.ts";
import { toReview } from "../utils/transform.ts";

export type Props = PaginationOptions & {
productsIds: string[];
};

/**
* @title Opiniões verificadas - Full Review for Product (Ratings and Reviews)
*/
export default async function productReviews(
config: Props,
_req: Request,
ctx: AppContext,
): Promise<Review[] | null> {
const client = createClient({ ...ctx });

if (!client) {
return null;
}

const reviewsResponse = await client.reviews({
productsIds: config.productsIds,
count: config?.count,
offset: config?.offset,
order: config?.order,
});

const reviews = reviewsResponse?.[0];
return reviews?.reviews?.map(toReview) ?? [];
}
6 changes: 4 additions & 2 deletions verified-reviews/manifest.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
import * as $$$0 from "./loaders/productDetailsPage.ts";
import * as $$$1 from "./loaders/productList.ts";
import * as $$$2 from "./loaders/productListingPage.ts";
import * as $$$3 from "./loaders/storeReview.ts";
import * as $$$3 from "./loaders/productReviews.ts";
import * as $$$4 from "./loaders/storeReview.ts";

const manifest = {
"loaders": {
"verified-reviews/loaders/productDetailsPage.ts": $$$0,
"verified-reviews/loaders/productList.ts": $$$1,
"verified-reviews/loaders/productListingPage.ts": $$$2,
"verified-reviews/loaders/storeReview.ts": $$$3,
"verified-reviews/loaders/productReviews.ts": $$$3,
"verified-reviews/loaders/storeReview.ts": $$$4,
},
"name": "verified-reviews",
"baseUrl": import.meta.url,
Expand Down
62 changes: 21 additions & 41 deletions verified-reviews/utils/client.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { context } from "deco/live.ts";

import { fetchAPI } from "../../utils/fetch.ts";
import { Ratings, Reviews, VerifiedReviewsFullReview } from "./types.ts";
import { Product } from "../../commerce/types.ts";

import { ConfigVerifiedReviews } from "../mod.ts";
import { context } from "deco/live.ts";

import { getRatingProduct, toReview } from "./transform.ts";
import { Ratings, Reviews, VerifiedReviewsFullReview } from "./types.ts";

export type ClientVerifiedReviews = ReturnType<typeof createClient>;

Expand All @@ -11,10 +15,10 @@ export interface PaginationOptions {
offset?: number;
order?:
| "date_desc"
| "date_ASC"
| "rate_DESC"
| "rate_ASC"
| "helpfulrating_DESC";
| "date_asc"
| "rate_desc"
| "rate_asc"
| "most_helpful";
}

const MessageError = {
Expand Down Expand Up @@ -87,75 +91,51 @@ export const createClient = (params: ConfigVerifiedReviews | undefined) => {

/** @description https://documenter.getpostman.com/view/2336519/SVzw6MK5#daf51360-c79e-451a-b627-33bdd0ef66b8 */
const reviews = ({
productId,
productsIds,
count = 5,
offset = 0,
order = "date_desc",
}: PaginationOptions & {
productId: string;
productsIds: string[];
}) => {
const payload = {
query: "reviews",
product: productId,
product: productsIds,
idWebsite: idWebsite,
plateforme: "br",
offset: offset,
limit: count,
order: order,
};

return fetchAPI<Reviews>(`${baseUrl}`, {
return fetchAPI<Reviews[]>(`${baseUrl}`, {
method: "POST",
body: JSON.stringify(payload),
});
};

const fullReview = async ({
productId,
productsIds,
count = 5,
offset = 0,
order,
}: PaginationOptions & {
productId: string;
productsIds: string[];
}): Promise<VerifiedReviewsFullReview> => {
try {
const response = await Promise.all([
rating({ productId }),
reviews({ productId, count, offset }),
ratings({ productsIds }),
reviews({ productsIds, count, offset, order }),
]);

const [responseRating, responseReview] = response.flat() as [
Ratings,
Reviews | null,
];

const currentRating = responseRating?.[productId]?.[0];
return {
aggregateRating: currentRating
? {
"@type": "AggregateRating",
ratingValue: Number(parseFloat(currentRating.rate).toFixed(1)),
reviewCount: Number(currentRating.count),
}
: undefined,
review: responseReview
? responseReview.reviews?.map((item) => ({
"@type": "Review",
author: [
{
"@type": "Author",
name: `${item.firstname} ${item.lastname}`,
},
],
datePublished: item.review_date,
reviewBody: item.review,
reviewRating: {
"@type": "AggregateRating",
ratingValue: Number(item.rate),
// this api does not support multiple reviews
reviewCount: 1,
},
}))
: [],
aggregateRating: getRatingProduct(responseRating),
review: responseReview ? responseReview.reviews?.map(toReview) : [],
};
} catch (error) {
if (context.isDeploy) {
Expand Down
37 changes: 25 additions & 12 deletions verified-reviews/utils/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,34 @@ import {
} from "../../commerce/types.ts";
import { Ratings, Review } from "./types.ts";

export const getRatingProduct = ({
ratings,
productId,
}: {
ratings: Ratings | undefined;
productId: string;
}): AggregateRating | undefined => {
const rating = ratings?.[productId]?.[0];
if (!rating) {
export const getRatingProduct = (
ratings: Ratings | undefined,
): AggregateRating | undefined => {
if (!ratings) {
return undefined;
}

return {
let weightedRating = 0;
let totalRatings = 0;

Object.entries(ratings ?? {}).forEach(([_, [rating]]) => {
const count = Number(rating.count);
const value = Number(parseFloat(rating.rate).toFixed(1));

totalRatings += count;
weightedRating += count * value;
});
matheusgr marked this conversation as resolved.
Show resolved Hide resolved

const aggregateRating: AggregateRating = {
"@type": "AggregateRating",
ratingCount: Number(rating.count),
ratingValue: Number(parseFloat(rating.rate).toFixed(1)),
ratingCount: totalRatings,
reviewCount: totalRatings,
ratingValue: totalRatings > 0
? Number((weightedRating / totalRatings).toFixed(1))
: 0,
};

return aggregateRating;
};

export const toReview = (review: Review): CommerceReview => ({
Expand All @@ -36,5 +47,7 @@ export const toReview = (review: Review): CommerceReview => ({
reviewRating: {
"@type": "AggregateRating",
ratingValue: Number(review.rate),
// this api does not support multiple reviews
reviewCount: 1,
},
});
2 changes: 1 addition & 1 deletion verified-reviews/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface Review {

export interface Reviews {
reviews: Review[];
status: number[];
stats: number[];
}

export interface VerifiedReviewsFullReview {
Expand Down
Loading