Added pages persistance (ugly, but temporary)
This commit is contained in:
parent
e13f37923d
commit
b7f5a0eb55
@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import { useLibrary, UseLibraryReturnTuple } from "./hooks/useLibrary";
|
||||
import { IBook } from "./types/book";
|
||||
import { BookT } from "./types/book";
|
||||
|
||||
export const BookListContext = React.createContext<UseLibraryReturnTuple>([
|
||||
{},
|
||||
(book: IBook) => {},
|
||||
(book: BookT) => {},
|
||||
[],
|
||||
]);
|
||||
|
||||
|
48
src/hooks/useBookState.ts
Normal file
48
src/hooks/useBookState.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BookState } from "~/types/book";
|
||||
import { loadBookState, saveBookState } from "~/utils/localStorage";
|
||||
|
||||
export const useBookState = (
|
||||
pagesReady: boolean,
|
||||
hash: string | undefined,
|
||||
goToPage: (pageNum: number) => void,
|
||||
currentPage: React.RefObject<number>
|
||||
): [boolean, BookState | undefined] => {
|
||||
const [state, setState] = useState<BookState>();
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (hash)
|
||||
loadBookState(
|
||||
hash,
|
||||
(obj) => setState(obj),
|
||||
() => setState({ currentPage: 0 })
|
||||
);
|
||||
}, [hash]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(Boolean(!ready && state?.currentPage && goToPage));
|
||||
if (!ready && state?.currentPage && pagesReady) {
|
||||
console.log("Go to", state.currentPage);
|
||||
goToPage(state.currentPage);
|
||||
console.log("Ready");
|
||||
setReady(true);
|
||||
} else if (hash && !ready && pagesReady && typeof state === "object") {
|
||||
saveBookState(hash, { currentPage: 0 });
|
||||
setReady(true);
|
||||
}
|
||||
}, [ready, state, goToPage]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (hash) {
|
||||
console.log(currentPage);
|
||||
if (ready && state) saveBookState(hash, state);
|
||||
else saveBookState(hash, { currentPage: currentPage.current || 0 });
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return [ready, state];
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { IBook } from "~/types/book";
|
||||
import { BookT } from "~/types/book";
|
||||
import {
|
||||
getBookHT,
|
||||
getHashList,
|
||||
@ -7,16 +7,16 @@ import {
|
||||
updateHashList,
|
||||
} from "~/utils/localStorage";
|
||||
|
||||
export type AddBookFT = (book: IBook) => void;
|
||||
export type AddBookFT = (book: BookT) => void;
|
||||
|
||||
export type UseLibraryReturnTuple = [
|
||||
Record<string, IBook> | null,
|
||||
Record<string, BookT> | null,
|
||||
AddBookFT,
|
||||
string[]
|
||||
];
|
||||
|
||||
export const useLibrary = (): UseLibraryReturnTuple => {
|
||||
const [library, setLibrary] = useState<Record<string, IBook> | null>(null);
|
||||
const [library, setLibrary] = useState<Record<string, BookT> | null>(null);
|
||||
const [hashList, setHashList] = useState<string[]>([]);
|
||||
|
||||
const addBook: AddBookFT = (book) => {
|
||||
|
@ -6,6 +6,7 @@ import styles from "./BookView.module.css";
|
||||
import { BookListContext } from "~/context";
|
||||
import { usePagination } from "~/hooks/usePagination";
|
||||
import { IPageProps } from "~/types/page";
|
||||
import { useBookState } from "~/hooks/useBookState";
|
||||
|
||||
export const BookView = ({ setLoading, loading }: IPageProps) => {
|
||||
useEffect(() => setLoading(true), []);
|
||||
@ -17,7 +18,7 @@ export const BookView = ({ setLoading, loading }: IPageProps) => {
|
||||
const pageContainerRef = useRef<HTMLDivElement>(null);
|
||||
const pageRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [ready, goToPage, currentPage, pagesNumber] = usePagination(
|
||||
const [pagesReady, goToPage, currentPage, pagesNumber] = usePagination(
|
||||
contentRef,
|
||||
pageContainerRef,
|
||||
pageRef,
|
||||
@ -31,8 +32,15 @@ export const BookView = ({ setLoading, loading }: IPageProps) => {
|
||||
currentPageRef.current = currentPage;
|
||||
}, [currentPage]);
|
||||
|
||||
const [bookStateReady, bs] = useBookState(
|
||||
pagesReady,
|
||||
params?.hash,
|
||||
goToPage,
|
||||
currentPageRef
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (ready) {
|
||||
if (bookStateReady) {
|
||||
setLoading(false);
|
||||
|
||||
const handleKey = ({ key }: KeyboardEvent) => {
|
||||
@ -48,7 +56,7 @@ export const BookView = ({ setLoading, loading }: IPageProps) => {
|
||||
|
||||
window.addEventListener("keydown", handleKey);
|
||||
}
|
||||
}, [ready]);
|
||||
}, [bookStateReady]);
|
||||
|
||||
const goPrev = () => goToPage(currentPage - 1);
|
||||
const goNext = () => goToPage(currentPage + 1);
|
||||
|
@ -2,10 +2,10 @@ import React from "react";
|
||||
|
||||
import styles from "./BookItem.module.css";
|
||||
|
||||
import { IBook } from "~/types/book";
|
||||
import { BookT } from "~/types/book";
|
||||
import { Link } from "wouter";
|
||||
|
||||
interface IBookItemProps extends IBook {}
|
||||
interface IBookItemProps extends BookT {}
|
||||
|
||||
export const BookItem = ({ author, title, cover, hash }: IBookItemProps) => {
|
||||
return (
|
||||
|
@ -1,9 +1,13 @@
|
||||
export const requiredBookProps = ["title", "author", "content"] as const;
|
||||
export const optionalBookProps = ["cover", "hash"] as const;
|
||||
|
||||
export type IBook = {
|
||||
export type BookT = {
|
||||
[key in typeof requiredBookProps[number]]: string;
|
||||
} &
|
||||
{
|
||||
[key in typeof optionalBookProps[number]]: string | undefined;
|
||||
};
|
||||
|
||||
export type BookState = {
|
||||
currentPage: number;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IBook, requiredBookProps } from "~/types/book";
|
||||
import { BookT, requiredBookProps } from "~/types/book";
|
||||
|
||||
import { API_URL } from "~/constants";
|
||||
|
||||
@ -39,7 +39,7 @@ export const submitFile = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const validateResponse = (content: unknown): content is IBook => {
|
||||
export const validateResponse = (content: unknown): content is BookT => {
|
||||
if (content && typeof content === "object")
|
||||
for (const key of requiredBookProps)
|
||||
if (!(key in content)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IBook } from "~/types/book";
|
||||
import { BookState, BookT } from "~/types/book";
|
||||
import { isArrOfStr } from "~/types/utils";
|
||||
import { validateResponse } from "~/utils/api";
|
||||
|
||||
@ -17,7 +17,7 @@ export const getHashList = () => {
|
||||
};
|
||||
|
||||
export const getBookHT = (hashList: string[]) => {
|
||||
const bookHT: Record<string, IBook> = {};
|
||||
const bookHT: Record<string, BookT> = {};
|
||||
|
||||
hashList.forEach((hash) => {
|
||||
try {
|
||||
@ -31,7 +31,7 @@ export const getBookHT = (hashList: string[]) => {
|
||||
return bookHT;
|
||||
};
|
||||
|
||||
export const saveBook = (key: string, book: IBook) =>
|
||||
export const saveBook = (key: string, book: BookT) =>
|
||||
localStorage.setItem(key, JSON.stringify(book));
|
||||
|
||||
export const updateHashList = (hashList: string[]) =>
|
||||
@ -78,3 +78,37 @@ export const savePages = (
|
||||
width: number,
|
||||
pages: number[]
|
||||
) => localStorage.setItem(hashStr(hash, height, width), JSON.stringify(pages));
|
||||
|
||||
export const validateBookState = (obj: unknown): obj is BookState =>
|
||||
Boolean(
|
||||
obj &&
|
||||
typeof obj === "object" &&
|
||||
!Array.isArray(obj) &&
|
||||
"currentPage" in obj
|
||||
);
|
||||
|
||||
export const loadBookState = (
|
||||
hash: string,
|
||||
cb: (bookState: BookState) => void,
|
||||
ecb: () => void
|
||||
) => {
|
||||
const str = localStorage.getItem(hash + "-state");
|
||||
|
||||
if (str) {
|
||||
try {
|
||||
const obj: unknown = JSON.parse(str);
|
||||
|
||||
if (validateBookState(obj)) {
|
||||
cb(obj);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
ecb();
|
||||
};
|
||||
|
||||
export const saveBookState = (hash: string, state: BookState) =>
|
||||
localStorage.setItem(hash + "-state", JSON.stringify(state));
|
||||
|
Loading…
x
Reference in New Issue
Block a user