Skip to content

Commit

Permalink
feat: add history page
Browse files Browse the repository at this point in the history
  • Loading branch information
conganhhcmus committed Mar 16, 2024
1 parent 9c81a5a commit a8b7bfd
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 36 deletions.
4 changes: 4 additions & 0 deletions public/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,9 @@
"added":"Added!",
"added-text":"Your data has been added.",
"genres-comic-title": "Read comic at",
"history-reading": "History Reading",
"reading": "Reading",
"continue-reading": "Continue Reading",
"delete-all": "Delete All",
"description_0": "The largest online comic reading website updated continuously every day - Join reading and discussing with more than 10 million members 🎉 at YouthBook ❤️💛💚"
}
5 changes: 5 additions & 0 deletions public/language/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,10 @@
"added":"Đã thêm!",
"added-text":"Dữ liệu đã được thêm.",
"genres-comic-title": "Truyện Thể loại",
"history-reading": "Lịch sử đọc truyện",
"reading": "Đang đọc",
"not-found-history": "Không tìm thấy lịch sử",
"continue-reading": "Đọc tiếp",
"delete-all": "Xóa tất cả",
"description_0": "Web đọc truyện tranh online lớn nhất được cập nhật liên tục mỗi ngày - Cùng tham gia đọc truyện và thảo luận với hơn 10 triệu thành viên 🎉 tại YouthBook ❤️💛💚"
}
8 changes: 4 additions & 4 deletions src/apis/comic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ const comicApis = {
return apiClients.get<ComicData>(url, { params: paramsRequest });
},

getComicInfo(id: string | undefined) {
const url = COMICS_PATH.comics + `/${id ?? '-1'}`;
getComicInfo(id: string = '-1') {
const url = COMICS_PATH.comics + `/${id}`;
return apiClients.get<Comic>(url);
},

updateComic(id: string | undefined, comic: ComicModel) {
const url = COMICS_PATH.comics + `/${id ?? '-1'}`;
updateComic(id: string = '-1', comic: ComicModel) {
const url = COMICS_PATH.comics + `/${id}`;
return apiClients.put<Comic>(url, { ...comic });
},

Expand Down
2 changes: 1 addition & 1 deletion src/components/Preview/ListPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface ListPreviewProps {

const ListPreview = ({ data, className }: ListPreviewProps) => {
return (
<ul className={className || 'mt-5 grid grid-cols-2 gap-3 gap-y-5 sm:grid-cols-3 md:grid-cols-4'}>
<ul className={className || 'mt-5 grid grid-cols-3 gap-3 gap-y-5 sm:grid-cols-4 md:grid-cols-5'}>
{data &&
data.map((item) => (
<li key={item._id}>
Expand Down
12 changes: 6 additions & 6 deletions src/components/Preview/TopPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const TopPreview = ({ data, top = 7 }: TopPreviewProps) => {
{data.slice(0, top).map((item, index) => (
<li
key={item._id}
className="flex items-center gap-3 border-b border-dashed border-[#ededed] dark:border-gray-600">
className="flex items-center gap-2 border-b border-dashed border-[#ededed] dark:border-gray-600">
<Link
to={`${APP_PATH.comics}/${item._id}`}
title={item.name}
Expand All @@ -30,27 +30,27 @@ const TopPreview = ({ data, top = 7 }: TopPreviewProps) => {
src={item.thumbnail}
alt={item.name}
title={item.name}
className="h-[50px] w-20 object-cover object-center"
className="w-20 object-cover object-center"
onError={({ currentTarget }) => {
currentTarget.onerror = null;
currentTarget.src = imgError;
}}
/>
</Link>
<div className="flex items-start gap-3">
<div className="flex items-start gap-2">
<span
className={`-mt-[2px] h-[22px] w-[22px] flex-shrink-0 rounded-full text-center
className={`h-[22px] w-[22px] flex-shrink-0 rounded-full text-center
${index === 0 && ' bg-[#feda00] text-white'}
${index === 1 && ' bg-[#feaf00] text-white'}
${index === 2 && ' bg-[#fe8f00] text-white'}
${index > 2 && ' bg-[#eeecec] text-black/70 dark:bg-gray-600 dark:text-white/70'}`}>
{index + 1}
</span>
<div className="-mt-[2px]">
<div className="-mt-[6px]">
<Link
title={item.name}
to={`${APP_PATH.comics}/${item._id}`}
className="line-clamp-1 text-base font-semibold leading-4 text-black hover:text-primary dark:text-white dark:hover:text-primary">
className="text-base font-semibold leading-4 text-black hover:text-primary dark:text-white dark:hover:text-primary">
{item.name}
</Link>
<p className="ml-[1px] line-clamp-1 text-sm leading-5 text-gray-400">
Expand Down
7 changes: 7 additions & 0 deletions src/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ const MainLayout = () => {
}
}, [callRequest, navigate, userInfoPayload]);

useEffect(() => {
window.scroll({
top: 0,
behavior: 'smooth',
});
}, []);

return (
<div className="grid h-full min-h-screen grid-cols-1 place-content-between">
<header
Expand Down
38 changes: 34 additions & 4 deletions src/pages/ChapterDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { Helmet } from 'react-helmet-async';
import { useQuery } from 'react-query';
import { useNavigate, useParams } from 'react-router';
import { NotFound } from './NotFound';
import { useEffect } from 'react';
import { addLocalDb } from '@/utils/indexedDB';
import { INDEXED_DB } from '@/constants/settings';
import comicApis from '@/apis/comic';
import moment from 'moment';

const ChapterDetail: React.FC = () => {
const { chapterId } = useParams();
Expand All @@ -36,8 +41,33 @@ const ChapterDetail: React.FC = () => {

const dataChapter = chapterResultData?.data.data || [];

const { data: comicResultData } = useQuery({
queryKey: ['getComicInfo', { comicId: chapterDetail?.comicId }],
queryFn: () => comicApis.getComicInfo(chapterDetail?.comicId),
staleTime: 3 * 60 * 1000,
enabled: !!chapterDetail && !!chapterDetail.comicId,
});

const comicDetail = comicResultData?.data;
const currentIndex = dataChapter.findIndex((chapter) => chapter._id === chapterDetail?._id);

useEffect(() => {
if (chapterDetail && comicDetail) {
const data = {
id: comicDetail._id,
name: comicDetail.name,
thumbnail: comicDetail.thumbnail,
description: comicDetail.description,
time: moment().format('hh:mm - DD/MM/YYY'),
chapter_id: chapterDetail._id,
reading_at: new Date().getTime(),
last_reading: chapterDetail.name,
};

addLocalDb(data, INDEXED_DB.collection.history);
}
}, [chapterDetail, comicDetail]);

const onChangeChapter = (e: React.ChangeEvent<HTMLSelectElement>) => {
e.preventDefault();
const chapter = dataChapter.find((x) => x._id === e.target.value);
Expand Down Expand Up @@ -83,9 +113,9 @@ const ChapterDetail: React.FC = () => {
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
fillRule="evenodd"
d="M7.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l2.293 2.293a1 1 0 010 1.414z"
clip-rule="evenodd"></path>
clipRule="evenodd"></path>
</svg>
<p className="ml-2">{translate('prev')}</p>
</div>
Expand Down Expand Up @@ -118,9 +148,9 @@ const ChapterDetail: React.FC = () => {
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
fillRule="evenodd"
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
clip-rule="evenodd"></path>
clipRule="evenodd"></path>
</svg>
</div>
</button>
Expand Down
39 changes: 23 additions & 16 deletions src/pages/ComicDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import { useQuery } from 'react-query';
import { useParams } from 'react-router';
import { NotFound } from './NotFound';
import { Link, createSearchParams } from 'react-router-dom';
import { APP_PATH } from '@/constants/path';
import { APP_PATH, TOP_COMICS } from '@/constants/path';
import imgError from '@/assets/icons/error.webp';
import RatingStar from '@/components/RatingStar';
import { formatCurrency } from '@/utils/format';
import { useEffect, useRef, useState } from 'react';
import { ListChapter } from '@/components/Comics';
import { ComicHorizontal, ListChapter } from '@/components/Comics';
import useReadChapter from '@/hooks/useReadChapter';
import { isEnabledRead } from '@/utils/comic';
import useAlertMsg from '@/hooks/useAlertMsg';
import useRequestParams from '@/hooks/useRequestParams';
import imgLoading from '@/assets/icons/loading.gif';

const ComicDetail: React.FC = () => {
const { comicId } = useParams();
Expand All @@ -27,15 +29,24 @@ const ComicDetail: React.FC = () => {
const translate = useTranslation(lang);
const { handleReadChapter, transactionList } = useReadChapter();
const { dontSupportAlert } = useAlertMsg();
const { defaultQueryParams } = useRequestParams();

const { data: comicResultData, isError } = useQuery({
queryKey: ['getComicInfo', { comicId }],
queryFn: () => comicApis.getComicInfo(comicId),
staleTime: 3 * 60 * 1000,
});

const { data: topWeeklyList } = useQuery({
queryKey: ['top-weekly-comics', defaultQueryParams],
queryFn: () => comicApis.topComics(TOP_COMICS.weekly, defaultQueryParams),
staleTime: 3 * 60 * 1000,
});

const dataComics = comicResultData?.data;

const topWeeklyData = topWeeklyList?.data.data;

useEffect(() => {
if (refDescription.current) {
setIsShow(refDescription.current.scrollHeight !== refDescription.current.clientHeight);
Expand Down Expand Up @@ -251,26 +262,22 @@ const ComicDetail: React.FC = () => {
{dataComics.chapters.length > 0 && <ListChapter data={dataComics.chapters} />}
</section>
</div>
{/* <div className="hidden w-[238px] flex-shrink-0 flex-col gap-6 md:flex">
<div className="hidden w-[238px] flex-shrink-0 flex-col gap-6 md:flex">
<>
<h4 className="flex items-center border px-5 py-3 pl-3 text-lg font-semibold text-black dark:border-gray-500 dark:text-white">
Top weekly
{translate('top-weekly')}
</h4>
<div className="-mt-6 flex min-h-[600px] flex-col border border-t-0 dark:border-gray-500">
{dataWeeklyComics &&
dataWeeklyComics.slice(0, 10).map((item, i) => (
<SuggestComics
key={item.id}
{topWeeklyData &&
topWeeklyData.slice(0, 10).map((item, i) => (
<ComicHorizontal
key={item._id}
index={i}
title={item.title}
src={item.thumbnail}
idChapter={item.last_chapter.id}
chapter={item.last_chapter.name}
genres={item.genres.map((item) => item.name) as [string]}
idComic={item.id}
item={item}
isSearchItem={false}
/>
))}
{!dataWeeklyComics && (
{!topWeeklyData && (
<div className="flex h-[300px] items-center justify-center gap-2 text-black dark:text-white">
<img
src={imgLoading}
Expand All @@ -282,7 +289,7 @@ const ComicDetail: React.FC = () => {
)}
</div>
</>
</div> */}
</div>
</div>
</div>
</div>
Expand Down
17 changes: 15 additions & 2 deletions src/pages/Genres.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useMemo } from 'react';
import { Helmet } from 'react-helmet-async';
import { useQuery } from 'react-query';
import { Link, createSearchParams } from 'react-router-dom';
import imgLoading from '@/assets/icons/loading.gif';

const Genres: React.FC = () => {
const { queryParams } = useRequestParams();
Expand All @@ -19,13 +20,13 @@ const Genres: React.FC = () => {

const type = useMemo(() => (queryParams.type !== undefined ? queryParams.type : 'all'), [queryParams.type]);

const { data: genresResultData } = useQuery({
const { data: genresResultData, isLoading: isLoadingGenres } = useQuery({
queryKey: ['getFullGenres'],
queryFn: () => genresApi.getFullGenres(),
staleTime: 3 * 60 * 1000,
});

const { data: comicResultData } = useQuery({
const { data: comicResultData, isLoading: isLoadingComic } = useQuery({
queryKey: ['getComicByGenres', queryParams],
queryFn: () => comicApis.getComicByGenres(queryParams),
staleTime: 3 * 60 * 1000,
Expand All @@ -41,6 +42,18 @@ const Genres: React.FC = () => {

const resultData = comicResultData?.data;

if (isLoadingGenres || isLoadingComic)
return (
<div className="flex h-[300px] items-center justify-center gap-2 text-black dark:text-white">
<img
src={imgLoading}
alt="loading icon"
loading="lazy"
/>
Loading...
</div>
);

return (
<>
<Helmet>
Expand Down
Loading

0 comments on commit a8b7bfd

Please sign in to comment.