grungnet/src/contexts/TokenDataContext.tsx

184 lines
5.0 KiB
TypeScript
Raw Normal View History

import React, {
useEffect,
useState,
useContext,
useCallback,
useMemo,
} from "react";
import { useLiveQuery } from "dexie-react-hooks";
import { useDatabase } from "./DatabaseContext";
import { removeGroupsItems } from "../helpers/group";
2021-07-12 22:59:28 +00:00
import { Token } from "../types/Token";
import { Group } from "../types/Group";
export type AddTokenEventHandler = (token: Token) => Promise<void>;
export type RemoveTokensEventHandler = (ids: string[]) => Promise<void>;
export type UpdateTokenEventHandler = (
id: string,
update: Partial<Token>
) => Promise<void>;
export type GetTokenEventHandler = (
tokenId: string
) => Promise<Token | undefined>;
2021-07-16 04:55:33 +00:00
export type UpdateTokenGroupsEventHandler = (groups: Group[]) => Promise<void>;
2021-07-12 22:59:28 +00:00
export type UpdateTokensHiddenEventHandler = (
ids: string[],
hideInSidebar: boolean
) => Promise<void>;
2021-07-17 08:39:49 +00:00
type TokenDataContextValue = {
2021-06-02 07:49:31 +00:00
tokens: Token[];
2021-07-12 22:59:28 +00:00
addToken: AddTokenEventHandler;
tokenGroups: Group[];
removeTokens: RemoveTokensEventHandler;
updateToken: UpdateTokenEventHandler;
getToken: GetTokenEventHandler;
2021-07-02 05:54:54 +00:00
tokensById: Record<string, Token>;
2021-06-02 07:49:31 +00:00
tokensLoading: boolean;
2021-07-12 22:59:28 +00:00
updateTokenGroups: UpdateTokenGroupsEventHandler;
updateTokensHidden: UpdateTokensHiddenEventHandler;
2021-07-02 05:54:54 +00:00
};
2021-06-02 07:49:31 +00:00
2021-07-02 05:54:54 +00:00
const TokenDataContext =
2021-07-17 08:39:49 +00:00
React.createContext<TokenDataContextValue | undefined>(undefined);
2021-07-02 05:54:54 +00:00
export function TokenDataProvider({ children }: { children: React.ReactNode }) {
const { database } = useDatabase();
2021-07-02 05:54:54 +00:00
const tokensQuery = useLiveQuery<Token[]>(
() => database?.table("tokens").toArray() || [],
[database]
);
const tokens = useMemo(() => tokensQuery || [], [tokensQuery]);
const tokensLoading = useMemo(() => !tokensQuery, [tokensQuery]);
const tokenGroupQuery = useLiveQuery(
() => database?.table("groups").get("tokens"),
[database]
);
2021-07-12 22:59:28 +00:00
const [tokenGroups, setTokenGroups] = useState<Group[]>([]);
useEffect(() => {
async function updateTokenGroups() {
2021-07-02 05:54:54 +00:00
const group = await database?.table("groups").get("tokens");
setTokenGroups(group.items);
}
if (database && tokenGroupQuery) {
updateTokenGroups();
}
}, [tokenGroupQuery, database]);
2021-07-12 22:59:28 +00:00
const getToken = useCallback<GetTokenEventHandler>(
async (tokenId) => {
2021-06-02 07:49:31 +00:00
let token = await database?.table("tokens").get(tokenId);
return token;
},
[database]
);
// Add token and add it to the token group
2021-07-12 22:59:28 +00:00
const addToken = useCallback<AddTokenEventHandler>(
async (token) => {
2021-07-02 05:54:54 +00:00
if (database) {
await database.table("tokens").add(token);
const group = await database.table("groups").get("tokens");
await database.table("groups").update("tokens", {
items: [{ id: token.id, type: "item" }, ...group.items],
});
}
},
[database]
);
2021-07-12 22:59:28 +00:00
const removeTokens = useCallback<RemoveTokensEventHandler>(
async (ids) => {
2021-07-02 05:54:54 +00:00
if (database) {
const tokens = await database.table("tokens").bulkGet(ids);
let assetIds = [];
for (let token of tokens) {
if (token.type === "file") {
assetIds.push(token.file);
assetIds.push(token.thumbnail);
}
2021-04-29 23:54:35 +00:00
}
2021-07-02 05:54:54 +00:00
const group = await database.table("groups").get("tokens");
let items = removeGroupsItems(group.items, ids);
await database.table("groups").update("tokens", { items });
2021-07-02 05:54:54 +00:00
await database.table("tokens").bulkDelete(ids);
await database.table("assets").bulkDelete(assetIds);
}
},
[database]
);
2021-07-12 22:59:28 +00:00
const updateToken = useCallback<UpdateTokenEventHandler>(
async (id, update) => {
2021-07-02 05:54:54 +00:00
await database?.table("tokens").update(id, update);
},
[database]
);
2021-07-12 22:59:28 +00:00
const updateTokensHidden = useCallback<UpdateTokensHiddenEventHandler>(
2021-07-02 05:54:54 +00:00
async (ids: string[], hideInSidebar: boolean) => {
await Promise.all(
2021-07-02 05:54:54 +00:00
ids.map((id) => database?.table("tokens").update(id, { hideInSidebar }))
);
},
[database]
);
2021-07-12 22:59:28 +00:00
const updateTokenGroups = useCallback<UpdateTokenGroupsEventHandler>(
async (groups: Group[]) => {
// Update group state immediately to avoid animation delay
setTokenGroups(groups);
2021-07-02 05:54:54 +00:00
await database?.table("groups").update("tokens", { items: groups });
},
[database]
);
2021-06-10 10:08:11 +00:00
const [tokensById, setTokensById] = useState({});
useEffect(() => {
2021-06-10 10:08:11 +00:00
setTokensById(
2021-07-02 05:54:54 +00:00
tokens.reduce((obj: Record<string, Token>, token: Token) => {
2021-06-10 10:08:11 +00:00
obj[token.id] = token;
return obj;
}, {})
);
}, [tokens]);
2021-07-17 08:39:49 +00:00
const value = {
tokens,
addToken,
tokenGroups,
removeTokens,
updateToken,
tokensById,
tokensLoading,
getToken,
updateTokenGroups,
2021-06-05 03:34:17 +00:00
updateTokensHidden,
};
return (
<TokenDataContext.Provider value={value}>
{children}
</TokenDataContext.Provider>
);
}
2021-07-17 08:39:49 +00:00
export function useTokenData() {
const context = useContext(TokenDataContext);
if (context === undefined) {
throw new Error("useTokenData must be used within a TokenDataProvider");
}
return context;
}
export default TokenDataContext;