mirror of
https://github.com/Radiquum/AniX.git
synced 2025-04-07 00:34:41 +00:00
feat: add popular comments viewing to the release page
This commit is contained in:
parent
237581a49c
commit
b9b0590dfe
5 changed files with 182 additions and 10 deletions
|
@ -114,9 +114,10 @@ const months = [
|
||||||
"дек.",
|
"дек.",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function unixToDate(unix: number) {
|
export function unixToDate(unix: number, type: string = "short") {
|
||||||
const date = new Date(unix * 1000);
|
const date = new Date(unix * 1000);
|
||||||
return date.getDate() + " " + months[date.getMonth()] + " " + date.getFullYear();
|
if (type === "short") return date.getDate() + " " + months[date.getMonth()] + " " + date.getFullYear();
|
||||||
|
if (type === "full") return date.getDate() + " " + months[date.getMonth()] + " " + date.getFullYear() + ", " + date.getHours() + ":" + date.getMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSeasonFromUnix = (unix: number) => {
|
export const getSeasonFromUnix = (unix: number) => {
|
||||||
|
|
97
app/components/Comments/Comments.Comment.tsx
Normal file
97
app/components/Comments/Comments.Comment.tsx
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import { unixToDate } from "#/api/utils";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { ENDPOINTS } from "#/api/config";
|
||||||
|
|
||||||
|
export const CommentsComment = (props: {
|
||||||
|
profile: { login: string; avatar: string; id: number };
|
||||||
|
comment: {
|
||||||
|
id: number;
|
||||||
|
timestamp: number;
|
||||||
|
message: string;
|
||||||
|
likes: number;
|
||||||
|
reply_count: number;
|
||||||
|
};
|
||||||
|
isSubComment?: boolean;
|
||||||
|
}) => {
|
||||||
|
const [replies, setReplies] = useState([]);
|
||||||
|
useEffect(() => {
|
||||||
|
async function _fetchReplies() {
|
||||||
|
await fetch(
|
||||||
|
`${ENDPOINTS.release.info}/comment/replies/${props.comment.id}/0?sort=2`
|
||||||
|
)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
setReplies(data.content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!props.isSubComment && props.comment.reply_count > 0) {
|
||||||
|
_fetchReplies();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="p-6 text-base bg-white rounded-lg dark:bg-gray-900">
|
||||||
|
<footer className="flex items-center justify-between mb-2">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<p className="inline-flex items-center mr-3 text-sm font-semibold text-gray-900 dark:text-white">
|
||||||
|
<img
|
||||||
|
className="w-6 h-6 mr-2 rounded-full"
|
||||||
|
src={props.profile.avatar}
|
||||||
|
alt={props.profile.login}
|
||||||
|
/>
|
||||||
|
{props.profile.login}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
<time
|
||||||
|
dateTime={props.comment.timestamp.toString()}
|
||||||
|
title={unixToDate(props.comment.timestamp, "full")}
|
||||||
|
>
|
||||||
|
{unixToDate(props.comment.timestamp)}
|
||||||
|
</time>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<p className="text-gray-500 whitespace-pre-wrap dark:text-gray-400">
|
||||||
|
{props.comment.message}
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center mt-4 space-x-4">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="flex items-center text-sm font-medium text-gray-500 hover:underline dark:text-gray-400"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="mr-1.5 w-3.5 h-3.5"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 20 18"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M5 5h5M5 8h2m6-3h2m-5 3h6m2-7H2a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3v5l5-5h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Ответить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{replies.length > 0 &&
|
||||||
|
replies.map((comment: any) => (
|
||||||
|
<CommentsComment
|
||||||
|
key={comment.id}
|
||||||
|
profile={comment.profile}
|
||||||
|
comment={{
|
||||||
|
id: comment.id,
|
||||||
|
timestamp: comment.timestamp,
|
||||||
|
message: comment.message,
|
||||||
|
likes: comment.likes_count,
|
||||||
|
reply_count: comment.reply_count,
|
||||||
|
}}
|
||||||
|
isSubComment={true}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
};
|
64
app/components/Comments/Comments.Main.tsx
Normal file
64
app/components/Comments/Comments.Main.tsx
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { Card, Button } from "flowbite-react";
|
||||||
|
import { CommentsComment } from "./Comments.Comment";
|
||||||
|
export const CommentsMain = (props: {
|
||||||
|
release_id: number;
|
||||||
|
token: string | null;
|
||||||
|
comments: any;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Card className="antialiased">
|
||||||
|
<div className="max-w-2xl px-4 mx-auto">
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<h2 className="text-lg font-bold text-gray-900 lg:text-2xl dark:text-white">
|
||||||
|
Комментарии
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm font-bold text-gray-600 dark:text-gray-300">
|
||||||
|
Популярные и актуальные
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
size={"sm"}
|
||||||
|
className="text-gray-500 border border-gray-600 rounded-full"
|
||||||
|
color="inline"
|
||||||
|
>
|
||||||
|
Показать все
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<form className="mb-6">
|
||||||
|
<div className="px-4 py-2 mb-4 bg-white border border-gray-200 rounded-lg rounded-t-lg dark:bg-gray-800 dark:border-gray-700">
|
||||||
|
<label htmlFor="comment" className="sr-only">
|
||||||
|
Ваш комментарий
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="comment"
|
||||||
|
rows={4}
|
||||||
|
className="w-full px-0 text-sm text-gray-900 border-0 focus:ring-0 focus:outline-none dark:text-white dark:placeholder-gray-400 dark:bg-gray-800"
|
||||||
|
placeholder="Написать комментарий..."
|
||||||
|
required
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
color="blue"
|
||||||
|
>
|
||||||
|
Оставить комментарий
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{props.comments.map((comment: any) => (
|
||||||
|
<CommentsComment
|
||||||
|
key={comment.id}
|
||||||
|
profile={comment.profile}
|
||||||
|
comment={{
|
||||||
|
id: comment.id,
|
||||||
|
timestamp: comment.timestamp,
|
||||||
|
message: comment.message,
|
||||||
|
likes: comment.likes_count,
|
||||||
|
reply_count: comment.reply_count,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
|
@ -97,7 +97,7 @@ export const ReleasePlayer = (props: { id: number }) => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
{!voiceoverInfo || !sourcesInfo || !episodeInfo ? (
|
{!voiceoverInfo || !sourcesInfo || !episodeInfo ? (
|
||||||
<div className="flex items-center justify-center w-full aspect-[16/12]">
|
<div className="flex items-center justify-center w-full aspect-video">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { ReleaseInfoUserList } from "#/components/ReleaseInfo/ReleaseInfo.UserLi
|
||||||
import { ReleaseInfoRating } from "#/components/ReleaseInfo/ReleaseInfo.Rating";
|
import { ReleaseInfoRating } from "#/components/ReleaseInfo/ReleaseInfo.Rating";
|
||||||
import { ReleaseInfoRelated } from "#/components/ReleaseInfo/ReleaseInfo.Related";
|
import { ReleaseInfoRelated } from "#/components/ReleaseInfo/ReleaseInfo.Related";
|
||||||
import { ReleaseInfoScreenshots } from "#/components/ReleaseInfo/ReleaseInfo.Screenshots";
|
import { ReleaseInfoScreenshots } from "#/components/ReleaseInfo/ReleaseInfo.Screenshots";
|
||||||
|
import { CommentsMain } from "#/components/Comments/Comments.Main";
|
||||||
|
|
||||||
export const ReleasePage = (props: any) => {
|
export const ReleasePage = (props: any) => {
|
||||||
const token = useUserStore((state) => state.token);
|
const token = useUserStore((state) => state.token);
|
||||||
|
@ -46,7 +47,7 @@ export const ReleasePage = (props: any) => {
|
||||||
return data ? (
|
return data ? (
|
||||||
<main className="container px-4 pt-4 pb-24 mx-auto sm:pb-4">
|
<main className="container px-4 pt-4 pb-24 mx-auto sm:pb-4">
|
||||||
<div className="grid grid-cols-[100%] lg:grid-cols-[70%_30%] gap-2 grid-flow-row-dense ">
|
<div className="grid grid-cols-[100%] lg:grid-cols-[70%_30%] gap-2 grid-flow-row-dense ">
|
||||||
<div className="[grid-column:1] [grid-row:1/span_2]">
|
<div className="[grid-column:1] [grid-row:span_2]">
|
||||||
<ReleaseInfoBasics
|
<ReleaseInfoBasics
|
||||||
image={data.release.image}
|
image={data.release.image}
|
||||||
title={{
|
title={{
|
||||||
|
@ -57,7 +58,7 @@ export const ReleasePage = (props: any) => {
|
||||||
note={data.release.note}
|
note={data.release.note}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="[grid-column:2]">
|
||||||
<ReleaseInfoInfo
|
<ReleaseInfoInfo
|
||||||
country={data.release.country}
|
country={data.release.country}
|
||||||
aired_on_date={data.release.aired_on_date}
|
aired_on_date={data.release.aired_on_date}
|
||||||
|
@ -77,7 +78,7 @@ export const ReleasePage = (props: any) => {
|
||||||
genres={data.release.genres}
|
genres={data.release.genres}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="-order-1 lg:order-none">
|
<div className="[grid-column:2] -order-1 lg:order-none">
|
||||||
<ReleaseInfoUserList
|
<ReleaseInfoUserList
|
||||||
userList={userList}
|
userList={userList}
|
||||||
isFavorite={userFavorite}
|
isFavorite={userFavorite}
|
||||||
|
@ -88,12 +89,12 @@ export const ReleasePage = (props: any) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{data.release.status.name.toLowerCase() != "анонс" && (
|
{data.release.status.name.toLowerCase() != "анонс" && (
|
||||||
<div className="[grid-column:1] [grid-row:3/span_4]">
|
<div className="[grid-column:1] [grid-row:span_4]">
|
||||||
<ReleasePlayer id={props.id} />
|
<ReleasePlayer id={props.id} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{data.release.status.name.toLowerCase() != "анонс" && (
|
{data.release.status.name.toLowerCase() != "анонс" && (
|
||||||
<div>
|
<div className="[grid-column:2]">
|
||||||
<ReleaseInfoRating
|
<ReleaseInfoRating
|
||||||
grade={data.release.grade}
|
grade={data.release.grade}
|
||||||
token={token}
|
token={token}
|
||||||
|
@ -110,12 +111,21 @@ export const ReleasePage = (props: any) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{data.release.screenshot_images.length > 0 && (
|
{data.release.screenshot_images.length > 0 && (
|
||||||
<div>
|
<div className="[grid-column:2]">
|
||||||
<ReleaseInfoScreenshots images={data.release.screenshot_images} />
|
<ReleaseInfoScreenshots images={data.release.screenshot_images} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className="[grid-column:1] [grid-row:span_2]">
|
||||||
|
<CommentsMain
|
||||||
|
release_id={props.id}
|
||||||
|
token={token}
|
||||||
|
comments={data.release.comments}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{data.release.related_releases.length > 0 && (
|
{data.release.related_releases.length > 0 && (
|
||||||
<div>
|
<div className="[grid-column:2] [grid-row:span_4]">
|
||||||
<ReleaseInfoRelated
|
<ReleaseInfoRelated
|
||||||
release_id={props.id}
|
release_id={props.id}
|
||||||
related={data.release.related}
|
related={data.release.related}
|
||||||
|
|
Loading…
Add table
Reference in a new issue