Switched from array to hash table as book list, some naming errors fixed

This commit is contained in:
Dmitriy Shishkov 2021-07-16 04:30:49 +05:00
parent 917b00ea18
commit 3ac74ef780
No known key found for this signature in database
GPG Key ID: 14358F96FCDD8060
6 changed files with 52 additions and 42 deletions

View File

@ -3,8 +3,9 @@ import { useLibrary, UseLibraryReturnTuple } from "./hooks/useLibrary";
import { IBook } from "./types/book"; import { IBook } from "./types/book";
export const BookListContext = React.createContext<UseLibraryReturnTuple>([ export const BookListContext = React.createContext<UseLibraryReturnTuple>([
[], {},
(book: IBook) => {}, (book: IBook) => {},
[],
]); ]);
export const BookListContextProvider: React.FC = ({ children }) => { export const BookListContextProvider: React.FC = ({ children }) => {

View File

@ -1,38 +1,46 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { IBook } from "~/types/book"; import { IBook } from "~/types/book";
import { import {
getBookList, getBookHT,
getTitleList, getHashList,
setBook, saveBook,
updateTitleList, updateHashList,
} from "~/utils/localStorage"; } from "~/utils/localStorage";
export type AddBookFT = (book: IBook) => void; export type AddBookFT = (book: IBook) => void;
export type UseLibraryReturnTuple = [IBook[], AddBookFT]; export type UseLibraryReturnTuple = [
Record<string, IBook>,
AddBookFT,
string[]
];
export const useLibrary = (): UseLibraryReturnTuple => { export const useLibrary = (): UseLibraryReturnTuple => {
const [bookList, setBookList] = useState<IBook[]>([]); const [library, setLibrary] = useState<Record<string, IBook>>({});
const [titleList, setTitleList] = useState<string[]>([]); const [hashList, setHashList] = useState<string[]>([]);
const addBook: AddBookFT = (book) => { const addBook: AddBookFT = (book) => {
const key = book.hash || Date.now().toString(); const key = book.hash || Date.now().toString();
if (key && !titleList.includes(key)) { if (key && !hashList.includes(key)) {
setTitleList([key, ...titleList]); setHashList([key, ...hashList]);
setBookList([book, ...bookList]); setLibrary((prev) => ({ [key]: book, ...prev }));
setBook(key, book); saveBook(key, book);
} }
}; };
useEffect(() => { useEffect(() => {
const receivedTitleList = getTitleList(); const receivedHashList = getHashList();
setTitleList(receivedTitleList); setHashList(receivedHashList);
setBookList(getBookList(receivedTitleList)); setLibrary(getBookHT(receivedHashList));
}, []); }, []);
useEffect(() => updateTitleList(titleList), [titleList]); useEffect(() => updateHashList(hashList), [hashList]);
return [bookList, addBook]; useEffect(() => {
console.log(library);
}, [library]);
return [library, addBook, hashList];
}; };

View File

@ -13,7 +13,7 @@ export const Bookshelf = () => {
<div className={styles.container}> <div className={styles.container}>
<div className={styles.scrollContainer}> <div className={styles.scrollContainer}>
<AddBook /> <AddBook />
{books.map((book, index) => ( {Object.values(books).map((book, index) => (
<BookItem key={book.hash} {...book} /> <BookItem key={book.hash} {...book} />
))} ))}
</div> </div>

View File

@ -3,7 +3,7 @@ import { useLocation } from "wouter";
import plusIcon from "~/assets/plus.svg"; import plusIcon from "~/assets/plus.svg";
import styles from "./UploadForm.module.css"; import styles from "./UploadForm.module.css";
import { submitFile, validateResponse, validState } from "~/api"; import { submitFile, validateResponse, validState } from "~/utils/api";
import { BookListContext } from "~/context"; import { BookListContext } from "~/context";
export const UploadForm = () => { export const UploadForm = () => {

View File

@ -1,6 +1,6 @@
import { IBook, requiredBookProps } from "~/types/book"; import { IBook, requiredBookProps } from "~/types/book";
import { API_URL } from "./constants"; import { API_URL } from "~/constants";
export const validState = (file: File | undefined): file is File => { export const validState = (file: File | undefined): file is File => {
if (!file) throw new Error("Book file is required. Please, attach one"); if (!file) throw new Error("Book file is required. Please, attach one");
@ -42,8 +42,11 @@ export const submitFile = async (
export const validateResponse = (content: unknown): content is IBook => { export const validateResponse = (content: unknown): content is IBook => {
if (content && typeof content === "object") if (content && typeof content === "object")
for (const key of requiredBookProps) for (const key of requiredBookProps)
if (!(key in content)) if (!(key in content)) {
throw new Error(`${key} is not specified in server response`); if (import.meta.env.NODE_ENV === "development")
console.log(`${key} is not specified in server response`);
return false;
}
return true; return true;
}; };

View File

@ -1,33 +1,31 @@
import { IBook } from "~/types/book"; import { IBook } from "~/types/book";
import { isArrOfStr } from "~/types/utils"; import { isArrOfStr } from "~/types/utils";
import { validateResponse } from "~/api"; import { validateResponse } from "~/utils/api";
export const getTitleList = () => { export const getHashList = () => {
const titleListStr = localStorage.getItem("list") || "[]"; const hashListStr = localStorage.getItem("list") || "[]";
const titleList: unknown = JSON.parse(titleListStr); const hashList: unknown = JSON.parse(hashListStr);
if (isArrOfStr(titleList)) return titleList; if (isArrOfStr(hashList)) return hashList;
else { else {
localStorage.setItem("list", "[]"); localStorage.setItem("list", "[]");
return []; return [];
} }
}; };
export const getBookList = (titleList: string[]) => export const getBookHT = (hashList: string[]) => {
titleList const bookHT: Record<string, IBook> = {};
.map<unknown>((hash) => JSON.parse(localStorage.getItem(hash) || "{}"))
.filter((obj): obj is IBook => {
try {
return validateResponse(obj);
} catch (err) {
if (import.meta.env.NODE_ENV === "development")
console.log(err.message);
return false;
}
});
export const setBook = (key: string, book: IBook) => hashList.forEach((hash) => {
const obj: unknown = JSON.parse(localStorage.getItem(hash) || "{}");
if (validateResponse(obj)) bookHT[hash] = obj;
});
return bookHT;
};
export const saveBook = (key: string, book: IBook) =>
localStorage.setItem(key, JSON.stringify(book)); localStorage.setItem(key, JSON.stringify(book));
export const updateTitleList = (titleList: string[]) => export const updateHashList = (hashList: string[]) =>
localStorage.setItem("list", JSON.stringify(titleList)); localStorage.setItem("list", JSON.stringify(hashList));