Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/GenerateNU/platnm into frie…
Browse files Browse the repository at this point in the history
…nds_rating_page
  • Loading branch information
ddusichka committed Dec 4, 2024
2 parents 9468ace + e033795 commit 3045234
Show file tree
Hide file tree
Showing 20 changed files with 519 additions and 71 deletions.
46 changes: 46 additions & 0 deletions backend/internal/service/handler/reviews/get_media_reviews.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package reviews
import (
"fmt"
"platnm/internal/models"
"sort"

"github.com/gofiber/fiber/v2"
)
Expand Down Expand Up @@ -43,6 +44,51 @@ func (h *Handler) GetReviewsByMediaId(c *fiber.Ctx, mediaType string) error {
return c.Status(fiber.StatusOK).JSON(response)
}

func (h *Handler) GetTopReviewsByMediaId(c *fiber.Ctx, mediaType string) error {
var id = c.Params("id")

// Even though we are paginating the reviews we need to get all the reviews in order to calculate average rating
// Fetch the review based on ID and media type
reviews, err := h.reviewRepository.GetReviewsByMediaID(c.Context(), id, mediaType)
if err != nil {
// If error, log it and return 500
fmt.Println(err.Error(), "from transactions err ")
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Unable to retrieve reviews",
})
}

var scores []float64

for _, r := range reviews {
rating := float64(r.Rating)
scores = append(scores, rating)
}

var rating = getAve(scores)

// Calculate upvote-downvote scores for sorting
sort.Slice(reviews, func(i, j int) bool {
scoreI := reviews[i].ReviewStat.Upvotes
scoreJ := reviews[j].ReviewStat.Upvotes
return scoreI > scoreJ // Sort descending by score
})

// Take the top 10 reviews
topReviews := reviews
// if len(reviews) > 5 {
// topReviews = reviews[:5]
// }

response := Response{
AvgRating: rating,
TotalCount: len(reviews),
Reviews: topReviews,
}

return c.Status(fiber.StatusOK).JSON(response)
}

func paginate(reviews []*models.Preview, limit int, offset int) []*models.Preview {
var start = offset * limit
var end = (offset * limit) + limit
Expand Down
6 changes: 6 additions & 0 deletions backend/internal/service/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ func setupRoutes(app *fiber.App, repo *storage.Repository, config config.Config)
r.Get("/track/:id", func(c *fiber.Ctx) error {
return reviewHandler.GetReviewsByMediaId(c, "track")
})
r.Get("/album/top/:id", func(c *fiber.Ctx) error {
return reviewHandler.GetTopReviewsByMediaId(c, "album")
})
r.Get("/track/top/:id", func(c *fiber.Ctx) error {
return reviewHandler.GetTopReviewsByMediaId(c, "track")
})
r.Get("/track/:userId/:mediaId", func(c *fiber.Ctx) error {
return reviewHandler.GetUserReviewOfTrack(c)
})
Expand Down
42 changes: 34 additions & 8 deletions frontend/app/MediaPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React, { useState, useEffect, useCallback } from "react";
import { StyleSheet, ScrollView, View, Text } from "react-native";
import { useFocusEffect, useLocalSearchParams } from "expo-router";
import {
StyleSheet,
ScrollView,
View,
Text,
TouchableOpacity,
} from "react-native";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import axios from "axios";
import Histogram from "@/components/media/Histogram";
import YourRatings from "@/components/media/YourRatings";
Expand All @@ -10,15 +16,18 @@ import ReviewStats from "@/components/media/ReviewStats";
import ReviewPreview from "@/components/ReviewPreview";

import SkeletonLoader from "expo-skeleton-loader";
import { useAuthContext } from "@/components/AuthProvider";

export default function MediaPage() {
const [media, setMedia] = useState<Media>();
const [reviews, setReviews] = useState<Preview[]>([]);
const [reviewsLoading, setReviewsLoading] = useState<boolean>(true);
const [avgRating, setAvgRating] = useState<number | null>(null);
const [totalCount, setTotalCount] = useState<number>(0);
const [ratingDistributions, setRatingDistributions] = useState<
RatingDistribution[]
>([]);
const { userId } = useAuthContext();

const BASE_URL = process.env.EXPO_PUBLIC_BASE_URL;
const { mediaId, mediaType } = useLocalSearchParams<{
Expand Down Expand Up @@ -68,11 +77,12 @@ export default function MediaPage() {
useCallback(() => {
if (media) {
axios
.get(`${BASE_URL}/reviews/${mediaType}/${mediaId}`)
.get(`${BASE_URL}/reviews/${mediaType}/top/${mediaId}`)
.then((response) => {
setReviews(response.data.reviews);
setReviewsLoading(false);
setAvgRating(Math.round(response.data.avgRating) || null);
setTotalCount(response.data.totalCount);
})
.catch((error) => console.error(error));
}
Expand Down Expand Up @@ -146,10 +156,26 @@ export default function MediaPage() {
) : (
<View style={styles.bodyContainer}>
<View style={styles.titleContainer}>
{avgRating && (
<ReviewStats rating={avgRating} reviews={reviews} />
)}
<TouchableOpacity
style={styles.titleContainer}
onPress={() =>
router.push({
pathname: "/MediaReviewsPage",
params: {
media_id: mediaId,
user_id: userId,
media_type: mediaType,
filter: "all",
},
})
}
>
{avgRating && (
<ReviewStats rating={avgRating} count={totalCount} />
)}
</TouchableOpacity>
</View>

{ratingDistributions && ratingDistributions.length > 0 && (
<Histogram distribution={ratingDistributions} />
)}
Expand All @@ -158,7 +184,7 @@ export default function MediaPage() {
<FriendRatings media_id={mediaId} media_type={mediaType} />
</View>
<View>
{reviews?.map((review) => (
{reviews?.slice(0, 5).map((review) => (
<ReviewPreview
key={review.review_id}
preview={{
Expand All @@ -167,7 +193,7 @@ export default function MediaPage() {
created_at: new Date(review.created_at),
updated_at: new Date(review.updated_at),
media_title: media.title,
tags: ["Excitement"],
tags: review.tags,
media_artist: media.artist_name,
media_cover: media.cover,
}}
Expand Down
63 changes: 50 additions & 13 deletions frontend/app/MediaReviewsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ const MediaReviewsPage = () => {
const [allReviews, setAllReviews] = useState<Preview[]>([]);
const [mediaStats, setMediaStats] = useState<{
userScore: number;
userRatings: number;
friendScore: number;
friendRatings: number;
avgScore: Number;
totalRatings: number;
}>({
userScore: 0,
userRatings: 0,
friendScore: 0,
friendRatings: 0,
avgScore: 0,
totalRatings: 0,
});
Expand All @@ -41,17 +45,16 @@ const MediaReviewsPage = () => {
useEffect(() => {
const fetchAll = async () => {
try {
console.log(`${BASE_URL}/reviews/${media_type}/${media_id}`);
const response = await axios.get(
`${BASE_URL}/reviews/${media_type}/${media_id}`,
);
setAllReviews(response.data.reviews);
setMediaStats({
userScore: 4.2,
friendScore: mediaStats.friendScore,

setMediaStats((prev) => ({
...prev,
avgScore: response.data.avgRating || 0,
totalRatings: response.data.totalCount || 0,
});
}));
} catch (error) {
console.error(error);
}
Expand Down Expand Up @@ -82,17 +85,23 @@ const MediaReviewsPage = () => {
setUserReviews(reviews);

// Calculate the average score
const totalScore = reviews.reduce(
const totalScore = response.data.reduce(
(sum: any, review: { rating: any }) => sum + review.rating,
0,
); // Sum of all ratings
const averageScore =
reviews.length > 0 ? totalScore / reviews.length : 0; // Avoid division by 0

// Update userScore in mediaStats
<<<<<<< HEAD
setMediaStats((prevStats) => ({
...prevStats,
friendScore: averageScore,
=======
setMediaStats((prev) => ({
...prev,
userScore: averageScore,
userRatings: reviews.length,
>>>>>>> e0337957225e2f562083ca3e106fcf9fcc42395d
}));
} catch (error) {
console.error(error);
Expand Down Expand Up @@ -190,10 +199,30 @@ const MediaReviewsPage = () => {
<Text style={styles.scoreLabel}>Avg Rating</Text>
</View>
)}
<Text style={styles.totalRatings}>
{formatLargeNumber(mediaStats.totalRatings)}
</Text>
<Text style={styles.totalRatingsText}>Total Ratings</Text>
{selectedFilter === "you" && (
<>
<Text style={styles.totalRatings}>
{formatLargeNumber(mediaStats.userRatings)}
</Text>
<Text style={styles.totalRatingsText}>Your Ratings</Text>
</>
)}
{selectedFilter === "friend" && (
<>
<Text style={styles.totalRatings}>
{formatLargeNumber(mediaStats.friendRatings)}
</Text>
<Text style={styles.totalRatingsText}>Friends Ratings</Text>
</>
)}
{selectedFilter === "all" && (
<>
<Text style={styles.totalRatings}>
{formatLargeNumber(mediaStats.totalRatings)}
</Text>
<Text style={styles.totalRatingsText}>Total Ratings</Text>
</>
)}
</View>
</View>
<Filter
Expand All @@ -203,21 +232,25 @@ const MediaReviewsPage = () => {
/>
<View>
{selectedFilter === "you" && (
<View>
<View style={styles.reviews}>
{userReviews.map((review, index) => {
return <ReviewPreview key={index} preview={review} />;
})}
</View>
)}
{selectedFilter === "friend" && (
<<<<<<< HEAD
<View>
{friendsReviews && friendsReviews.length > 0 && friendsReviews.map((review, index) => {
return <ReviewPreview key={index} preview={review} />;
})}
</View>
=======
<View style={styles.reviews}></View> // TODO ALEX: Map each fetched review to a ReviewPreview component which will take care of the rest
>>>>>>> e0337957225e2f562083ca3e106fcf9fcc42395d
)}
{selectedFilter === "all" && (
<View>
<View style={styles.reviews}>
{allReviews.map((review, index) => {
return <ReviewPreview key={index} preview={review} />;
})}
Expand Down Expand Up @@ -299,6 +332,10 @@ const styles = StyleSheet.create({
reviewsContainer: {
backgroundColor: "#fff",
},
reviews: {
width: "90%",
alignSelf: "center",
},
});

export default MediaReviewsPage;
22 changes: 11 additions & 11 deletions frontend/app/ReviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ import {
Modal,
KeyboardAvoidingView,
} from "react-native";
import Rating0 from "@/assets/images/Ratings/Radial-0.svg";
import Rating1 from "@/assets/images/Ratings/Radial-1.svg";
import Rating2 from "@/assets/images/Ratings/Radial-2.svg";
import Rating3 from "@/assets/images/Ratings/Radial-3.svg";
import Rating4 from "@/assets/images/Ratings/Radial-4.svg";
import Rating5 from "@/assets/images/Ratings/Radial-5.svg";
import Rating6 from "@/assets/images/Ratings/Radial-6.svg";
import Rating7 from "@/assets/images/Ratings/Radial-7.svg";
import Rating8 from "@/assets/images/Ratings/Radial-8.svg";
import Rating9 from "@/assets/images/Ratings/Radial-9.svg";
import Rating10 from "@/assets/images/Ratings/Radial-10.svg";
import Rating0 from "@/assets/images/Ratings/Property0.svg";
import Rating1 from "@/assets/images/Ratings/Property1.svg";
import Rating2 from "@/assets/images/Ratings/Property2.svg";
import Rating3 from "@/assets/images/Ratings/Property3.svg";
import Rating4 from "@/assets/images/Ratings/Property4.svg";
import Rating5 from "@/assets/images/Ratings/Property5.svg";
import Rating6 from "@/assets/images/Ratings/Property6.svg";
import Rating7 from "@/assets/images/Ratings/Property7.svg";
import Rating8 from "@/assets/images/Ratings/Property8.svg";
import Rating9 from "@/assets/images/Ratings/Property9.svg";
import Rating10 from "@/assets/images/Ratings/Property10.svg";
import Downvote from "@/assets/images/ReviewPreview/downvote.svg";
import Upvote from "@/assets/images/ReviewPreview/upvote.svg";
import Comment from "@/assets/images/ReviewPreview/comment.svg";
Expand Down
29 changes: 29 additions & 0 deletions frontend/assets/images/Ratings/Property0.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions frontend/assets/images/Ratings/Property1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3045234

Please sign in to comment.