Skip to content

Commit

Permalink
add rating and comment section of games
Browse files Browse the repository at this point in the history
  • Loading branch information
kadirchan committed Nov 10, 2024
1 parent 4c8ff5f commit c5438a2
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 29 deletions.
122 changes: 122 additions & 0 deletions src/renderer/components/commentSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
'use client';
import { useState, useEffect } from 'react';
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination';
import { Avatar } from '@/components/ui/avatar';
import { Separator } from '@/components/ui/separator';

import RatingDisplay from './ratingDisplay';
import Jazzicon from 'react-jazzicon';

import { useGamesStore } from '../lib/stores/gameStore';
import { base58Decode } from '../lib/utils';
import { fetchComments } from '../lib/api';

export default function CommentSection({ game }: { game: Game }) {
const [comments, setComments] = useState<IComment[]>([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [currentLimit, setCurrentLimit] = useState(10);
const [totalComments, setTotalComments] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [postTrigger, setPostTrigger] = useState(false);
const gameStore = useGamesStore();

useEffect(() => {
const loadComments = async () => {
setIsLoading(true);
try {
const { comments, totalComments, totalPages } = await fetchComments(
game.gameId,
currentPage,
currentLimit,
);

setComments(comments);
setTotalPages(totalPages);
setTotalComments(totalComments);
} catch (error) {
console.error('Failed to fetch comments:', error);
} finally {
setIsLoading(false);
}
};

loadComments();
}, [game.gameId, currentPage, postTrigger]);

return (
<div className="p-4">
<h2 className="text-xl font-semibold mb-4">
Comments ( {totalComments} )
</h2>
<Separator />
<div className="mt-6 space-y-6">
{comments.length > 0 ? (
comments.map((comment) => (
<div key={comment._id} className="flex space-x-4">
<Avatar>
<Jazzicon
diameter={40}
seed={base58Decode(comment.user.publicKey)}
/>
</Avatar>
<div className="flex flex-col gap-1 items-start">
<div className="flex items-center space-x-2">
<span className="font-medium">
{comment.user.publicKey.slice(0, 4) +
' ... ' +
comment.user.publicKey.slice(-4)}
</span>
<span className="text-sm text-gray-500">
{new Date(comment.createdAt).toLocaleString()}
</span>
</div>
<RatingDisplay rating={comment.rating} decimals={false} />
<p>{comment.content}</p>
</div>
</div>
))
) : (
<p>No comments yet. Be the first to comment!</p>
)}
{isLoading && <p>Loading comments...</p>}
</div>
{currentPage <= totalPages && (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => {
if (currentPage > 1) {
setCurrentPage((prevPage) => prevPage - 1);
setPostTrigger((prev) => !prev);
}
}}
/>
</PaginationItem>
<PaginationItem>
<PaginationLink isActive={false}>{currentPage}</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext
onClick={() => {
if (currentPage < totalPages) {
setCurrentPage((prevPage) => prevPage + 1);
setPostTrigger((prev) => !prev);
}
}}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
)}
</div>
);
}
31 changes: 12 additions & 19 deletions src/renderer/components/featured.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,25 +80,18 @@ export default function Featured() {
className=" w-5 h-5 inline-block"
/>
</CardShadow>

{!userStore.library.includes(game.gameId || -1) ? (
<Button
variant={'default'}
onClick={(event) => {
event.stopPropagation();
window.electron.ipcRenderer.sendMessage(
'redirect-buy-game',
[game?.name],
);
}}
>
Buy Game
</Button>
) : (
<div className=" flex flex-row items-center text-green-700">
<Check /> <span>Owned</span>
</div>
)}
<Button
variant={'default'}
onClick={(event) => {
event.stopPropagation();
window.electron.ipcRenderer.sendMessage(
'redirect-buy-game',
[game?.name],
);
}}
>
Visit Store
</Button>
</div>
</CardFooter>
</Card>
Expand Down
24 changes: 14 additions & 10 deletions src/renderer/components/game-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import {
CarouselContent,
CarouselItem,
} from '@/components/ui/carousel';
import { ChevronLeft, Download } from 'lucide-react';
import { ChevronLeft } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { useNavigate, useParams } from 'react-router-dom';
import { useGamesStore } from '../lib/stores/gameStore';
import { Separator } from '@/components/ui/separator';
import { API_URL } from '@/env';
import RatingDisplay from './ratingDisplay';
import CommentSection from './commentSection';

export default function GameDetail() {
const { gameName } = useParams();
Expand All @@ -19,8 +21,6 @@ export default function GameDetail() {
const game = gameStore.games.find((game) => game.name === gameName);
const imageCount = game?.imageCount || 1;

const handleDownload = () => {};

return (
<div>
<div className=" grid grid-cols-5 w-full p-4">
Expand Down Expand Up @@ -68,7 +68,15 @@ export default function GameDetail() {
<h1 className=" text-3xl font-bold p-4">{game?.name}</h1>
<div className=" text-base mt-8">{game?.description}</div>

<div>Total Reviews: 5 (4.3)</div>
<div className=" flex flex-col items-center justify-center">
<RatingDisplay
rating={game?.averageRating || 0}
decimals={true}
/>
<div className=" flex items-center text-sm">
Total Reviews: {game?.ratingCount}
</div>
</div>

<div>
{Array.from(game?.tags || []).map((tag, index) => (
Expand Down Expand Up @@ -114,13 +122,9 @@ export default function GameDetail() {
);
}}
>
Buy Game
Visit Store
</Button>
</div>
<Button variant={'link'} className="">
<Download size={24} onClick={handleDownload} />
Download Game
</Button>
</div>
</div>
</div>
Expand Down Expand Up @@ -158,7 +162,7 @@ export default function GameDetail() {
</div>
<div className=" col-span-1"></div>
</div>
{/* <CommentSection /> */}
<CommentSection game={game!} />
</div>
);
}
32 changes: 32 additions & 0 deletions src/renderer/components/ratingDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Star } from 'lucide-react';

export default function RatingDisplay({
rating,
decimals,
}: {
rating: number;
decimals: boolean;
}) {
return (
<div className="flex flex-row gap-1 items-center justify-center">
<div className="flex space-x-1">
{[1, 2, 3, 4, 5].map((star) => {
const fillPercentage = Math.min(Math.max(rating - (star - 1), 0), 1);

return (
<div key={star} className="relative w-4 h-4">
<Star size={16} className="text-gray-300 absolute top-0 left-0" />
<div
className="overflow-hidden absolute top-0 left-0"
style={{ width: `${fillPercentage * 100}%` }}
>
<Star size={16} className="text-yellow-500" />
</div>
</div>
);
})}
</div>
{decimals && <div className=" text-sm">({rating.toFixed(1)})</div>}
</div>
);
}

0 comments on commit c5438a2

Please sign in to comment.