Added pages persistance (ugly, but temporary)

This commit is contained in:
Dmitriy Shishkov 2021-07-24 20:06:40 +03:00
parent e13f37923d
commit b7f5a0eb55
No known key found for this signature in database
GPG Key ID: 14358F96FCDD8060
8 changed files with 111 additions and 17 deletions

View File

@ -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
View 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];
};

View File

@ -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) => {

View File

@ -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);

View File

@ -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 (

View File

@ -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;
};

View File

@ -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)) {

View File

@ -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));