diff --git a/app/components/ReleaseInfo/ReleaseInfo.Basics.tsx b/app/components/ReleaseInfo/ReleaseInfo.Basics.tsx new file mode 100644 index 0000000..53ba3e4 --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.Basics.tsx @@ -0,0 +1,35 @@ +import { Card } from "flowbite-react"; +export const ReleaseInfoBasics = (props: { + image: string; + title: { ru: string; original: string }; + note: string | null; + description: string; +}) => { + return ( + +
+ +
+
+

+ {props.title.ru} +

+

+ {props.title.original} +

+
+ {props.note && ( +
+
+
+ )} +

{props.description}

+
+
+
+ ); +}; diff --git a/app/components/ReleaseInfo/ReleaseInfo.Info.tsx b/app/components/ReleaseInfo/ReleaseInfo.Info.tsx new file mode 100644 index 0000000..61e4e6d --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.Info.tsx @@ -0,0 +1,154 @@ +import { Card, Table } from "flowbite-react"; +import { ReleaseInfoSearchLink } from "#/components/ReleaseInfo/ReleaseInfo.SearchLink"; +import { unixToDate, getSeasonFromUnix, minutesToTime } from "#/api/utils"; +const weekDay = [ + "_", + "каждый понедельник", + "каждый вторник", + "каждую среду", + "каждый четверг", + "каждую пятницу", + "каждую субботу", + "каждое воскресенье", +]; +const YearSeason = ["_", "Зима", "Весна", "Лето", "Осень"]; +export const ReleaseInfoInfo = (props: { + country: string | null; + aired_on_date: number | null; + year: number | null; + episodes: { total: number | null; released: number | null }; + season: number; + status: string; + duration: number; + category: string; + broadcast: number; + studio: string | null; + author: string | null; + director: string | null; + genres: string; +}) => { + return ( + + + + + + {props.country ? ( + props.country.toLowerCase() == "япония" ? ( + + ) : ( + + ) + ) : ( + + )} + + + {props.country && props.country} + {(props.aired_on_date != 0 || props.year) && ", "} + {props.aired_on_date != 0 && + `${getSeasonFromUnix(props.aired_on_date)} `} + {props.year && `${props.year} г.`} + + + + + + + + {props.episodes.released ? props.episodes.released : "?"} + {"/"} + {props.episodes.total ? props.episodes.total + " эп. " : "? эп. "} + {props.duration != 0 && `по ${minutesToTime(props.duration)}`} + + + + + + + + {props.category} + {", "} + {props.broadcast == 0 + ? props.status.toLowerCase() + : `выходит ${weekDay[props.broadcast]}`} + + + + + + + + {props.studio && ( + <> + {"Студия: "} + {props.studio + .split(", ") + .map((studio: string, index: number) => { + return ( +
+ {index > 0 && ", "} + +
+ ); + })} + {(props.author || props.director) && ", "} + + )} + {props.author && ( + <> + {"Автор: "} + + {props.director && ", "} + + )} + {props.director && ( + <> + {"Режиссёр: "} + + + )} +
+
+ + + + + + {props.genres && + props.genres.split(", ").map((genre: string, index: number) => { + return ( +
+ {index > 0 && ", "} + +
+ ); + })} +
+
+ {props.status.toLowerCase() == "анонс" && ( + + + + + + {props.aired_on_date != 0 ? ( + unixToDate(props.aired_on_date) + ) : props.year ? ( + <> + {props.season && props.season != 0 + ? `${YearSeason[props.season]} ` + : ""} + {props.year && `${props.year} г.`} + + ) : ( + "Скоро" + )} + + + )} +
+
+
+ ); +}; diff --git a/app/components/ReleaseInfo/ReleaseInfo.Rating.tsx b/app/components/ReleaseInfo/ReleaseInfo.Rating.tsx new file mode 100644 index 0000000..379b422 --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.Rating.tsx @@ -0,0 +1,114 @@ +import { + Card, + Rating, + Flowbite, + Button, + CustomFlowbiteTheme, +} from "flowbite-react"; +import { numberDeclension } from "#/api/utils"; + +const RatingTheme: CustomFlowbiteTheme = { + ratingAdvanced: { + progress: { + base: "mx-4 h-5 w-3/4 rounded bg-gray-200 dark:bg-gray-700", + }, + }, +}; +export const ReleaseInfoRating = (props: { + grade: number; + token: string | null; + votes: { + 1: number; + 2: number; + 3: number; + 4: number; + 5: number; + total: number; + user: number | null; + }; +}) => { + return ( + +
+ + +

+ {props.grade.toFixed(2)} из 5 +

+
+ {props.token && ( + <> + + {props.votes.user ? ( +
+

+ ваша оценка: {props.votes.user} +

+ +
+ ) : ( + + )} + + )} +
+

+ {props.votes.total}{" "} + {numberDeclension(props.votes.total, "голос", "голоса", "голосов")} +

+ + + 5 + + + 4 + + + 3 + + + 2 + + + 1 + + +
+ ); +}; diff --git a/app/components/ReleaseInfo/ReleaseInfo.Related.tsx b/app/components/ReleaseInfo/ReleaseInfo.Related.tsx new file mode 100644 index 0000000..85cd3bf --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.Related.tsx @@ -0,0 +1,49 @@ +"use client"; + +import { Card, Carousel, CustomFlowbiteTheme } from "flowbite-react"; +import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLink"; +import Link from "next/link"; + +const CarouselTheme: CustomFlowbiteTheme["carousel"] = { + root: { + base: "relative h-full w-full max-w-[300px]", + }, +}; + +export const ReleaseInfoRelated = (props: { + release_id: number; + related: any; + related_releases: any; +}) => { + return ( + +
+

Связанные релизы

+ {props.related && ( + +
+

Показать все

+ +
+ + )} +
+
+ + {props.related_releases + .filter((release: any) => { + if (release.id == props.release_id) { + return false; + } + return true; + }) + .map((release: any) => { + return ( + + ); + })} + +
+
+ ); +}; diff --git a/app/components/ReleaseInfo/ReleaseInfo.Screenshots.tsx b/app/components/ReleaseInfo/ReleaseInfo.Screenshots.tsx new file mode 100644 index 0000000..74d02e6 --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.Screenshots.tsx @@ -0,0 +1,15 @@ +import { Card, Carousel } from "flowbite-react"; + +export const ReleaseInfoScreenshots = (props: { + images: string[]; +}) => { + return ( + + + {props.images.map((image: string, index: number) => ( + + ))} + + + ); +}; diff --git a/app/components/ReleaseInfo/ReleaseInfo.UserList.tsx b/app/components/ReleaseInfo/ReleaseInfo.UserList.tsx new file mode 100644 index 0000000..ae4e151 --- /dev/null +++ b/app/components/ReleaseInfo/ReleaseInfo.UserList.tsx @@ -0,0 +1,88 @@ +import { Card, Dropdown, Button } from "flowbite-react"; +import { ENDPOINTS } from "#/api/config"; + +const lists = [ + { list: 0, name: "Не смотрю" }, + { list: 1, name: "Смотрю" }, + { list: 2, name: "В планах" }, + { list: 3, name: "Просмотрено" }, + { list: 4, name: "Отложено" }, + { list: 5, name: "Брошено" }, +]; + +const DropdownTheme = { + floating: { + target: + "flex-1 bg-blue-600 enabled:hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800", + }, +}; + +export const ReleaseInfoUserList = (props: { + userList: number; + isFavorite: boolean; + release_id: number; + token: string | null; + setUserList: any; + setIsFavorite: any; +}) => { + function _addToFavorite() { + if (props.token) { + props.setIsFavorite(!props.isFavorite); + if (props.isFavorite) { + fetch( + `${ENDPOINTS.user.favorite}/delete/${props.release_id}?token=${props.token}` + ); + } else { + fetch( + `${ENDPOINTS.user.favorite}/add/${props.release_id}?token=${props.token}` + ); + } + } + } + + function _addToList(list: number) { + if (props.token) { + props.setUserList(list); + fetch( + `${ENDPOINTS.user.bookmark}/add/${list}/${props.release_id}?token=${props.token}` + ); + } + } + + return ( + + {props.token ? ( +
+ + {lists.map((list) => ( + _addToList(list.list)} + > + {list.name} + + ))} + + +
+ ) : ( +

Войдите что-бы добавить в избранное или список

+ )} +
+ ); +}; diff --git a/app/components/ReleaseLink/ReleaseLink.tsx b/app/components/ReleaseLink/ReleaseLink.tsx index 335f95b..6d6c640 100644 --- a/app/components/ReleaseLink/ReleaseLink.tsx +++ b/app/components/ReleaseLink/ReleaseLink.tsx @@ -1,7 +1,7 @@ import { ReleaseLink169 } from "./ReleaseLink.16_9"; import { ReleaseLinkPoster } from "./ReleaseLink.Poster"; -export const ReleaseLink = (props: any) => { +export const ReleaseLink = (props: {type?: "16_9"|"poster"}) => { const type = props.type || "16_9"; if (type == "16_9") { diff --git a/app/components/ReleasePlayer/ReleasePlayer.tsx b/app/components/ReleasePlayer/ReleasePlayer.tsx index 96e3a78..36bb9aa 100644 --- a/app/components/ReleasePlayer/ReleasePlayer.tsx +++ b/app/components/ReleasePlayer/ReleasePlayer.tsx @@ -119,7 +119,7 @@ export const ReleasePlayer = (props: { id: number }) => { > {voiceoverInfo.map((voiceover: any) => ( setSelectedVoiceover(voiceover)} > {voiceover.name} @@ -132,7 +132,7 @@ export const ReleasePlayer = (props: { id: number }) => { > {sourcesInfo.map((source: any) => ( setSelectedSource(source)} > {source.name} @@ -156,7 +156,7 @@ export const ReleasePlayer = (props: { id: number }) => { ? ButtonThemeActive : ButtonThemeInactive }`} - key={episode.id} + key={`episode_${episode.position}`} onClick={() => { setSelectedEpisode(episode); episode.is_watched = true; diff --git a/app/pages/Release.tsx b/app/pages/Release.tsx index f1f8536..a367118 100644 --- a/app/pages/Release.tsx +++ b/app/pages/Release.tsx @@ -5,65 +5,15 @@ import { Spinner } from "#/components/Spinner/Spinner"; const fetcher = (...args: any) => fetch([...args] as any).then((res) => res.json()); import { useUserStore } from "#/store/auth"; -import { - Card, - Dropdown, - Button, - Carousel, - Rating, - Flowbite, - CustomFlowbiteTheme, -} from "flowbite-react"; import { useEffect, useState } from "react"; -import { - unixToDate, - getSeasonFromUnix, - minutesToTime, - numberDeclension, -} from "#/api/utils"; -import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLink"; + +import { ReleaseInfoBasics } from "#/components/ReleaseInfo/ReleaseInfo.Basics"; +import { ReleaseInfoInfo } from "#/components/ReleaseInfo/ReleaseInfo.Info"; import { ReleasePlayer } from "#/components/ReleasePlayer/ReleasePlayer"; -import { ENDPOINTS } from "#/api/config"; -import { Table } from "flowbite-react"; -import { ReleaseInfoSearchLink } from "#/components/ReleaseInfo/ReleaseInfo.SearchLink"; -import Link from "next/link"; - -const lists = [ - { list: 0, name: "Не смотрю" }, - { list: 1, name: "Смотрю" }, - { list: 2, name: "В планах" }, - { list: 3, name: "Просмотрено" }, - { list: 4, name: "Отложено" }, - { list: 5, name: "Брошено" }, -]; - -const weekDay = [ - "_", - "каждый понедельник", - "каждый вторник", - "каждую среду", - "каждый четверг", - "каждую пятницу", - "каждую субботу", - "каждое воскресенье", -]; - -const YearSeason = ["_", "Зима", "Весна", "Лето", "Осень"]; - -const DropdownTheme = { - floating: { - target: - "flex-1 bg-blue-600 enabled:hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800", - }, -}; - -const RatingTheme: CustomFlowbiteTheme = { - ratingAdvanced: { - progress: { - base: "mx-4 h-5 w-3/4 rounded bg-gray-200 dark:bg-gray-700", - }, - }, -}; +import { ReleaseInfoUserList } from "#/components/ReleaseInfo/ReleaseInfo.UserList"; +import { ReleaseInfoRating } from "#/components/ReleaseInfo/ReleaseInfo.Rating"; +import { ReleaseInfoRelated } from "#/components/ReleaseInfo/ReleaseInfo.Related"; +import { ReleaseInfoScreenshots } from "#/components/ReleaseInfo/ReleaseInfo.Screenshots"; export const ReleasePage = (props: any) => { const token = useUserStore((state) => state.token); @@ -93,378 +43,86 @@ export const ReleasePage = (props: any) => { } }, [data]); - function _addToFavorite() { - if (data && token) { - setUserFavorite(!userFavorite); - if (userFavorite) { - fetch( - `${ENDPOINTS.user.favorite}/delete/${data.release.id}?token=${token}` - ); - } else { - fetch( - `${ENDPOINTS.user.favorite}/add/${data.release.id}?token=${token}` - ); - } - } - } - - function _addToList(list: number) { - if (data && token) { - setUserList(list); - fetch( - `${ENDPOINTS.user.bookmark}/add/${list}/${data.release.id}?token=${token}` - ); - } - } - return data ? (
-
-
- -
- -
-
- {data.release.title_ru && ( -

- {data.release.title_ru} -

- )} - {data.release.title_original && ( -

- {data.release.title_original} -

- )} -
- {data.release.note && ( -
-
-
- )} - {data.release.description &&

{data.release.description}

} -
-
-
- {data.release.status.name.toLowerCase() != "анонс" && ( +
+
+ +
+
+ +
+
+ +
+ {data.release.status.name.toLowerCase() != "анонс" && ( +
- )} -
-
- - - - - - {data.release.country ? ( - data.release.country.toLowerCase() == "япония" ? ( - - ) : ( - - ) - ) : ( - - )} - - - {data.release.country && data.release.country} - {(data.release.aired_on_date != 0 || data.release.year) && - ", "} - {data.release.aired_on_date != 0 && - `${getSeasonFromUnix(data.release.aired_on_date)} `} - {data.release.year && `${data.release.year} г.`} - - - - - - - - {data.release.episodes_released - ? data.release.episodes_released - : "?"} - {"/"} - {data.release.episodes_total - ? data.release.episodes_total + " эп. " - : "? эп. "} - {data.release.duration != 0 && - `по ${minutesToTime(data.release.duration)}`} - - - - - - - - {data.release.category.name} - {", "} - {data.release.broadcast == 0 - ? data.release.status.name.toLowerCase() - : `выходит ${weekDay[data.release.broadcast]}`} - - - - - - - - {data.release.studio && ( - <> - {"Студия: "} - {data.release.studio - .split(", ") - .map((studio: string, index: number) => { - return ( - <> - {index > 0 && ", "} - - - ); - })} - {(data.release.author || data.release.director) && ", "} - - )} - {data.release.author && ( - <> - {"Автор: "} - - {data.release.director && ", "} - - )} - {data.release.director && ( - <> - {"Режиссёр: "} - - - )} - - - - - - - - {data.release.genres && - data.release.genres - .split(", ") - .map((genre: string, index: number) => { - return ( - <> - {index > 0 && ", "} - - - ); - })} - - - {data.release.status.name.toLowerCase() == "анонс" && ( - - - - - - {data.release.aired_on_date != 0 ? ( - unixToDate(data.release.aired_on_date) - ) : data.release.year ? ( - <> - {data.release.season && data.release.season != 0 - ? `${YearSeason[data.release.season]} ` - : ""} - {data.release.year && `${data.release.year} г.`} - - ) : ( - "Скоро" - )} - - - )} - -
-
-
- {token && ( - -
- - {lists.map((list) => ( - _addToList(list.list)} - > - {list.name} - - ))} - - -
-
- )} - {data.release.status.name.toLowerCase() != "анонс" && ( - -
- - - - - - -

- {data.release.grade.toFixed(2)} из 5 -

-
- {token && ( - <> - - {data.release.your_vote ? ( -
-

- ваша оценка: {data.release.your_vote} -

- -
- ) : ( - - )} - - )} -
-

- {data.release.vote_count}{" "} - {numberDeclension( - data.release.vote_count, - "голос", - "голоса", - "голосов" - )} -

- - - 5 - - - 4 - - - 3 - - - 2 - - - 1 - - -
- )}
- {data.release.related_releases.length > 0 && ( - -
-
-

Связанные релизы

- {data.release.related && ( - -
-

Показать все

- -
- - )} -
-
- {data.release.related_releases.map((release) => { - if (release.id == data.release.id) return null; - return ; - })} -
-
-
- )} - {data.release.screenshot_images.length > 0 && ( - - - {data.release.screenshot_images.map( - (image: string, index: number) => ( - - ) - )} - - - )} -
-
+ )} + {data.release.status.name.toLowerCase() != "анонс" && ( +
+ +
+ )} + {data.release.screenshot_images.length > 0 && ( +
+ +
+ )} + {data.release.related_releases.length > 0 && ( +
+ +
+ )}
) : (