2021-04-30 11:56:37 +10:00
|
|
|
import React, { useEffect, useState, useContext, useCallback } from "react";
|
2020-05-19 16:21:01 +10:00
|
|
|
|
2021-02-06 13:32:38 +11:00
|
|
|
import { useAuth } from "./AuthContext";
|
|
|
|
|
import { useDatabase } from "./DatabaseContext";
|
2020-05-19 16:21:01 +10:00
|
|
|
|
2021-05-25 15:47:52 +10:00
|
|
|
import { applyObservableChange } from "../helpers/dexie";
|
2021-06-09 09:29:32 +10:00
|
|
|
import { removeGroupsItems } from "../helpers/group";
|
2021-05-25 15:47:52 +10:00
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
const TokenDataContext = React.createContext();
|
|
|
|
|
|
|
|
|
|
export function TokenDataProvider({ children }) {
|
2021-06-11 15:38:23 +10:00
|
|
|
const { database, databaseStatus } = useDatabase();
|
2021-02-06 13:32:38 +11:00
|
|
|
const { userId } = useAuth();
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
const [tokens, setTokens] = useState([]);
|
2020-11-26 16:29:10 +11:00
|
|
|
const [tokensLoading, setTokensLoading] = useState(true);
|
2021-05-09 12:04:31 +10:00
|
|
|
const [tokenGroups, setTokenGroups] = useState([]);
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
2020-10-23 22:16:18 +11:00
|
|
|
if (!userId || !database || databaseStatus === "loading") {
|
2020-05-19 16:21:01 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 19:03:36 +10:00
|
|
|
async function loadTokens() {
|
2021-06-11 15:38:23 +10:00
|
|
|
const storedTokens = await database.table("tokens").toArray();
|
2021-05-09 12:04:31 +10:00
|
|
|
setTokens(storedTokens);
|
|
|
|
|
const group = await database.table("groups").get("tokens");
|
2021-05-14 18:02:50 +10:00
|
|
|
const storedGroups = group.items;
|
2021-05-09 12:04:31 +10:00
|
|
|
setTokenGroups(storedGroups);
|
2020-11-26 16:29:10 +11:00
|
|
|
setTokensLoading(false);
|
2020-05-19 19:03:36 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loadTokens();
|
2021-06-11 15:38:23 +10:00
|
|
|
}, [userId, database, databaseStatus]);
|
2020-05-19 19:03:36 +10:00
|
|
|
|
2021-04-30 11:56:37 +10:00
|
|
|
const getToken = useCallback(
|
2021-01-22 14:59:05 +11:00
|
|
|
async (tokenId) => {
|
|
|
|
|
let token = await database.table("tokens").get(tokenId);
|
|
|
|
|
return token;
|
|
|
|
|
},
|
|
|
|
|
[database]
|
|
|
|
|
);
|
2020-09-11 16:56:40 +10:00
|
|
|
|
2021-05-09 12:04:31 +10:00
|
|
|
// Add token and add it to the token group
|
2021-01-22 14:59:05 +11:00
|
|
|
const addToken = useCallback(
|
|
|
|
|
async (token) => {
|
|
|
|
|
await database.table("tokens").add(token);
|
2021-05-09 12:04:31 +10:00
|
|
|
const group = await database.table("groups").get("tokens");
|
2021-05-14 18:02:50 +10:00
|
|
|
await database.table("groups").update("tokens", {
|
|
|
|
|
items: [{ id: token.id, type: "item" }, ...group.items],
|
|
|
|
|
});
|
2021-01-22 14:59:05 +11:00
|
|
|
},
|
2021-04-30 11:56:37 +10:00
|
|
|
[database]
|
2021-01-22 14:59:05 +11:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const removeTokens = useCallback(
|
|
|
|
|
async (ids) => {
|
2021-04-30 09:54:35 +10:00
|
|
|
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-06-09 09:29:32 +10:00
|
|
|
|
|
|
|
|
const group = await database.table("groups").get("tokens");
|
|
|
|
|
let items = removeGroupsItems(group.items, ids);
|
|
|
|
|
await database.table("groups").update("tokens", { items });
|
|
|
|
|
|
2021-01-22 14:59:05 +11:00
|
|
|
await database.table("tokens").bulkDelete(ids);
|
2021-04-30 09:54:35 +10:00
|
|
|
await database.table("assets").bulkDelete(assetIds);
|
2021-01-22 14:59:05 +11:00
|
|
|
},
|
|
|
|
|
[database]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const updateToken = useCallback(
|
|
|
|
|
async (id, update) => {
|
2021-06-05 13:34:17 +10:00
|
|
|
await database.table("tokens").update(id, update);
|
2021-01-22 14:59:05 +11:00
|
|
|
},
|
|
|
|
|
[database]
|
|
|
|
|
);
|
|
|
|
|
|
2021-06-05 13:34:17 +10:00
|
|
|
const updateTokensHidden = useCallback(
|
|
|
|
|
async (ids, hideInSidebar) => {
|
|
|
|
|
// Update immediately to avoid UI delay
|
|
|
|
|
setTokens((prevTokens) => {
|
|
|
|
|
let newTokens = [...prevTokens];
|
|
|
|
|
for (let id of ids) {
|
|
|
|
|
const tokenIndex = newTokens.findIndex((token) => token.id === id);
|
|
|
|
|
newTokens[tokenIndex].hideInSidebar = hideInSidebar;
|
|
|
|
|
}
|
|
|
|
|
return newTokens;
|
|
|
|
|
});
|
2021-01-22 14:59:05 +11:00
|
|
|
await Promise.all(
|
2021-06-05 13:34:17 +10:00
|
|
|
ids.map((id) => database.table("tokens").update(id, { hideInSidebar }))
|
2021-01-22 14:59:05 +11:00
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
[database]
|
|
|
|
|
);
|
|
|
|
|
|
2021-05-09 12:04:31 +10:00
|
|
|
const updateTokenGroups = useCallback(
|
|
|
|
|
async (groups) => {
|
|
|
|
|
// Update group state immediately to avoid animation delay
|
|
|
|
|
setTokenGroups(groups);
|
2021-05-14 18:02:50 +10:00
|
|
|
await database.table("groups").update("tokens", { items: groups });
|
2021-05-09 12:04:31 +10:00
|
|
|
},
|
|
|
|
|
[database]
|
|
|
|
|
);
|
|
|
|
|
|
2021-02-14 18:35:42 +11:00
|
|
|
// Create DB observable to sync creating and deleting
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!database || databaseStatus === "loading") {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 18:31:24 +11:00
|
|
|
function handleTokenChanges(changes) {
|
2021-06-14 15:18:07 +10:00
|
|
|
// Pool token changes together to call a single state update at the end
|
|
|
|
|
let tokensCreated = [];
|
|
|
|
|
let tokensUpdated = {};
|
|
|
|
|
let tokensDeleted = [];
|
2021-02-14 18:35:42 +11:00
|
|
|
for (let change of changes) {
|
|
|
|
|
if (change.table === "tokens") {
|
|
|
|
|
if (change.type === 1) {
|
|
|
|
|
// Created
|
|
|
|
|
const token = change.obj;
|
2021-06-14 15:18:07 +10:00
|
|
|
tokensCreated.push(token);
|
2021-02-16 18:31:24 +11:00
|
|
|
} else if (change.type === 2) {
|
|
|
|
|
// Updated
|
|
|
|
|
const token = change.obj;
|
2021-06-14 15:18:07 +10:00
|
|
|
tokensUpdated[token.id] = token;
|
2021-02-14 18:35:42 +11:00
|
|
|
} else if (change.type === 3) {
|
|
|
|
|
// Deleted
|
|
|
|
|
const id = change.key;
|
2021-06-14 15:18:07 +10:00
|
|
|
tokensDeleted.push(id);
|
2021-02-14 18:35:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-09 12:04:31 +10:00
|
|
|
if (change.table === "groups") {
|
|
|
|
|
if (change.type === 2 && change.key === "tokens") {
|
2021-05-25 15:47:52 +10:00
|
|
|
const group = applyObservableChange(change);
|
|
|
|
|
const groups = group.items.filter((item) => item !== null);
|
|
|
|
|
setTokenGroups(groups);
|
2021-05-09 12:04:31 +10:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-14 18:35:42 +11:00
|
|
|
}
|
2021-06-14 15:18:07 +10:00
|
|
|
const tokensUpdatedArray = Object.values(tokensUpdated);
|
|
|
|
|
if (
|
|
|
|
|
tokensCreated.length > 0 ||
|
|
|
|
|
tokensUpdatedArray.length > 0 ||
|
|
|
|
|
tokensDeleted.length > 0
|
|
|
|
|
) {
|
|
|
|
|
setTokens((prevTokens) => {
|
|
|
|
|
let newTokens = [...tokensCreated, ...prevTokens];
|
|
|
|
|
for (let token of tokensUpdatedArray) {
|
|
|
|
|
const tokenIndex = newTokens.findIndex((t) => t.id === token.id);
|
|
|
|
|
if (tokenIndex > -1) {
|
|
|
|
|
newTokens[tokenIndex] = token;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return newTokens.filter((token) => !tokensDeleted.includes(token.id));
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-02-14 18:35:42 +11:00
|
|
|
}
|
|
|
|
|
|
2021-02-16 18:31:24 +11:00
|
|
|
database.on("changes", handleTokenChanges);
|
2021-02-14 18:35:42 +11:00
|
|
|
|
|
|
|
|
return () => {
|
2021-02-16 18:31:24 +11:00
|
|
|
database.on("changes").unsubscribe(handleTokenChanges);
|
2021-02-14 18:35:42 +11:00
|
|
|
};
|
|
|
|
|
}, [database, databaseStatus]);
|
|
|
|
|
|
2021-06-10 20:08:11 +10:00
|
|
|
const [tokensById, setTokensById] = useState({});
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setTokensById(
|
|
|
|
|
tokens.reduce((obj, token) => {
|
|
|
|
|
obj[token.id] = token;
|
|
|
|
|
return obj;
|
|
|
|
|
}, {})
|
|
|
|
|
);
|
|
|
|
|
}, [tokens]);
|
2020-05-22 20:43:07 +10:00
|
|
|
|
2020-05-19 19:03:36 +10:00
|
|
|
const value = {
|
|
|
|
|
tokens,
|
|
|
|
|
addToken,
|
2021-05-09 12:04:31 +10:00
|
|
|
tokenGroups,
|
2020-10-01 22:32:21 +10:00
|
|
|
removeTokens,
|
2020-05-19 19:03:36 +10:00
|
|
|
updateToken,
|
2020-05-22 20:43:07 +10:00
|
|
|
tokensById,
|
2020-11-26 16:29:10 +11:00
|
|
|
tokensLoading,
|
2021-04-30 11:56:37 +10:00
|
|
|
getToken,
|
2021-05-09 12:04:31 +10:00
|
|
|
updateTokenGroups,
|
2021-06-05 13:34:17 +10:00
|
|
|
updateTokensHidden,
|
2020-05-19 19:03:36 +10:00
|
|
|
};
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<TokenDataContext.Provider value={value}>
|
|
|
|
|
{children}
|
|
|
|
|
</TokenDataContext.Provider>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 13:32:38 +11:00
|
|
|
export function useTokenData() {
|
|
|
|
|
const context = useContext(TokenDataContext);
|
|
|
|
|
if (context === undefined) {
|
|
|
|
|
throw new Error("useTokenData must be used within a TokenDataProvider");
|
|
|
|
|
}
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
export default TokenDataContext;
|