Skip to content

Commit

Permalink
Fix tree timestamp loading function and improve tree list retrieval f…
Browse files Browse the repository at this point in the history
…rom the database.
  • Loading branch information
Jun-Murakami committed May 4, 2024
1 parent 0cd11bb commit 4f24f6c
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 94 deletions.
5 changes: 4 additions & 1 deletion src/components/ResponsiveDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ export function ResponsiveDrawer({ handleLogout }: { handleLogout: () => void })

// ツリーのリストから選択されたツリーを表示する
const handleListClick = async (treeId: UniqueIdentifier): Promise<void> => {
await loadCurrentTreeData(treeId);
if (currentTree === treeId) {
return;
}
setCurrentTree(treeId);
await loadCurrentTreeData(treeId);
if (isAccordionExpanded) {
// 0.5秒後にフォーカスをセット
setTimeout(() => {
Expand Down
35 changes: 27 additions & 8 deletions src/hooks/useDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const useDatabase = () => {
};

// ツリーのタイムスタンプを取得する関数 ---------------------------------------------------------------------------
const loadTreeTimeStampFromDb = async (targetTree: UniqueIdentifier): Promise<number | null> => {
const loadTreeTimestampFromDb = async (targetTree: UniqueIdentifier): Promise<number | null> => {
if (!uid || !targetTree) {
return null;
}
Expand Down Expand Up @@ -171,19 +171,38 @@ export const useDatabase = () => {
};

// データベースからツリーリストを取得する関数 ---------------------------------------------------------------------------
const loadTreesListFromDb = async (userId: string): Promise<string[] | null> => {
const loadTreesListFromDb = async (userId: string): Promise<TreesList> => {
const userTreeListRef = ref(getDatabase(), `users/${userId}/treeList`);
return await get(userTreeListRef)
.then((snapshot) => {
.then(async (snapshot) => {
if (snapshot.exists()) {
return snapshot.val();
let missingTrees: string[] = [];
const data: string[] = snapshot.val();
let treesListAccumulator: TreesList = [];
// 反復してツリー名をDBから取得
const promises = data.map(async (treeId) => {
const treeTitle = await loadTreeNameFromDb(treeId);
if (treeTitle) {
treesListAccumulator = [...treesListAccumulator, { id: treeId, name: treeTitle }];
} else {
console.log('ツリー名が取得できませんでした。' + treeId + 'のツリーは削除されている可能性があります。');
missingTrees = missingTrees ? [...missingTrees, treeId] : [treeId];
}
});
await Promise.all(promises);
// DBの順序に基づいてtreesListAccumulatorを並び替え
const orderedTreesList = data
.map((treeId) => treesListAccumulator.find((t) => t.id === treeId))
.filter((t): t is TreesListItem => t !== undefined);
return orderedTreesList;
} else {
console.log('ツリーリストが見つかりませんでした。');
return [];
}
console.log('ツリーリストのDBフェッチに失敗しました。スナップショットが存在しません。');
return null;
})
.catch((error) => {
console.log('ツリーリストのDBフェッチに失敗しました。\n\n' + error);
return null;
return [];
});
};

Expand Down Expand Up @@ -288,7 +307,7 @@ export const useDatabase = () => {
saveItemsDb,
saveTreesListDb,
saveCurrentTreeNameDb,
loadTreeTimeStampFromDb,
loadTreeTimestampFromDb,
loadTreesListFromDb,
loadTreeNameFromDb,
loadItemsFromDb,
Expand Down
24 changes: 15 additions & 9 deletions src/hooks/useIndexedDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { getFunctions, httpsCallable } from 'firebase/functions';
import { getDatabase, ref, set } from 'firebase/database';
import { isTreeItemArray, validateTreeItems, ensureChildrenProperty } from '../components/SortableTree/utilities';
import { useAppStateManagement } from './useAppStateManagement';
import { useTreeManagement } from './useTreeManagement';
import { useDatabase } from './useDatabase';
import { useError } from './useError';
import { useAppStateStore } from '../store/appStateStore';
Expand All @@ -22,23 +21,29 @@ export const useIndexedDb = () => {
const setQuickMemoText = useAppStateStore((state) => state.setQuickMemoText);
const localTimestamp = useAppStateStore((state) => state.localTimestamp);
const setLocalTimestamp = useAppStateStore((state) => state.setLocalTimestamp);
const treesList = useTreeStateStore((state) => state.treesList);
const setTreesList = useTreeStateStore((state) => state.setTreesList);
const showDialog = useDialogStore((state) => state.showDialog);

const { loadSettingsFromDb, loadQuickMemoFromDb } = useAppStateManagement();
const { loadTreesList } = useTreeManagement();
const { loadTreeTimeStampFromDb, loadAllTreesDataFromDb, loadTreeNameFromDb, loadMembersFromDb, loadItemsFromDb } = useDatabase();
const { loadTreesListFromDb,
loadTreeTimestampFromDb,
loadAllTreesDataFromDb,
loadTreeNameFromDb,
loadMembersFromDb,
loadItemsFromDb
} = useDatabase();
const { handleError } = useError();


// FirebaseRealtimeDatabaseとIndexedデータベースを同期する ------------------------------------------------
const syncDb = async () => {
if (!uid) {
return;
}
try {
setLocalTimestamp(Date.now());
await loadSettingsFromDb();
await loadQuickMemoFromDb();
await loadTreesList();
const treesListFromDb = await loadTreesListFromDb(uid);
await idb.appstate.clear();
await idb.appstate.put({
id: 1,
Expand All @@ -48,9 +53,9 @@ export const useIndexedDb = () => {
darkMode: darkMode,
hideDoneItems: hideDoneItems,
},
treesList: treesList,
treesList: treesListFromDb,
});
const allTreesData = await loadAllTreesDataFromDb(treesList);
const allTreesData = await loadAllTreesDataFromDb(treesListFromDb);
if (allTreesData) {
await idb.treestate.clear();
for (const treeData of allTreesData) {
Expand Down Expand Up @@ -86,6 +91,7 @@ export const useIndexedDb = () => {
}
}
}
setTreesList(treesListFromDb);
} catch (error) {
handleError(error);
}
Expand Down Expand Up @@ -401,7 +407,7 @@ export const useIndexedDb = () => {

// タイムスタンプを取得
try {
const treeTimestamp = await loadTreeTimeStampFromDb(targetTree);
const treeTimestamp = await loadTreeTimestampFromDb(targetTree);
if (treeTimestamp) {
treeData.timestamp = treeTimestamp;
}
Expand Down
38 changes: 27 additions & 11 deletions src/hooks/useObserve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ export const useObserve = () => {
const currentTreeName = useTreeStateStore((state) => state.currentTreeName);
const prevItems = useTreeStateStore((state) => state.prevItems);
const setPrevItems = useTreeStateStore((state) => state.setPrevItems);
const prevCurrentTree = useTreeStateStore((state) => state.prevCurrentTree);
const setPrevCurrentTree = useTreeStateStore((state) => state.setPrevCurrentTree);

const showDialog = useDialogStore((state) => state.showDialog);

const { loadTreesList, loadCurrentTreeData, handleLoadedContent } = useTreeManagement();
const { saveItemsDb } = useDatabase();
const { loadCurrentTreeData, handleLoadedContent } = useTreeManagement();
const { loadTreesListFromDb, saveItemsDb } = useDatabase();
const { syncDb,
checkAndSyncDb,
loadSettingsFromIdb,
Expand Down Expand Up @@ -86,7 +88,7 @@ export const useObserve = () => {
const currentLocalTimestamp = useAppStateStore.getState().localTimestamp;
if (serverTimestamp && serverTimestamp > currentLocalTimestamp) {
setLocalTimestamp(serverTimestamp);
await loadTreesList();
await loadTreesListFromDb(uid);
await saveTreesListIdb(treesList);
await loadQuickMemoFromDb();
// treesListを反復して、タイムスタンプをチェックし、最新のツリーをコピー
Expand Down Expand Up @@ -127,14 +129,28 @@ export const useObserve = () => {

// ローカルitemsの変更を監視し、データベースに保存 ---------------------------------------------------------------------------
useEffect(() => {
// ツリー変更時には前回のitemsを保存して終了
if (prevItems.length === 0) {
setPrevItems(items);
if ((!uid && !isOffline) || !currentTree || isEqual(items, prevItems)) {
return;
}
if ((!uid && !isOffline) || !currentTree || isEqual(items, prevItems)) {

if (currentTree !== prevCurrentTree) {
console.log('Tree changed. Saving items to database.');
if (prevItems.length > 0) {
const asyncFunc = async () => {
if (prevCurrentTree) {
await saveItemsIdb(prevItems, prevCurrentTree);
await saveItemsDb(prevItems, prevCurrentTree);
}
}
asyncFunc();
}
setPrevCurrentTree(currentTree);
setPrevItems([]);
return;
}

setPrevItems(items);
const targetTree = currentTree;
const debounceSave = setTimeout(() => {
try {
if (isOffline) {
Expand All @@ -152,16 +168,16 @@ export const useObserve = () => {
} else {
// オンラインモードの場合、データベースに保存
const asyncFunc = async () => {
await saveItemsIdb(items, currentTree);
await saveItemsDb(items, currentTree);
await saveItemsIdb(items, targetTree);
await saveItemsDb(items, targetTree);
}
asyncFunc();
}
setPrevItems(items);
setPrevItems([]);
} catch (error) {
handleError('ツリー内容の変更をデータベースに保存できませんでした。\n\n' + error);
}
}, 3000); // 3秒のデバウンス
}, 5000); // 3秒のデバウンス

// コンポーネントがアンマウントされるか、依存配列の値が変更された場合にタイマーをクリア
return () => clearTimeout(debounceSave);
Expand Down
66 changes: 1 addition & 65 deletions src/hooks/useTreeManagement.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback } from 'react';
import { UniqueIdentifier } from '@dnd-kit/core';
import { TreeItem, TreesList, TreesListItem, TreesListItemIncludingItems } from '../types/types';
import { TreeItem, TreesListItemIncludingItems } from '../types/types';
import { isTreeItemArray } from '../components/SortableTree/utilities';
import { initialItems, initialOfflineItems } from '../components/SortableTree/mock';
import { getFunctions, httpsCallable } from 'firebase/functions';
Expand Down Expand Up @@ -38,87 +38,30 @@ export const useTreeManagement = () => {
const setCurrentTreeName = useTreeStateStore((state) => state.setCurrentTreeName);
const currentTreeMembers = useTreeStateStore((state) => state.currentTreeMembers);
const setCurrentTreeMembers = useTreeStateStore((state) => state.setCurrentTreeMembers);
const prevCurrentTree = useTreeStateStore((state) => state.prevCurrentTree);
const setPrevCurrentTree = useTreeStateStore((state) => state.setPrevCurrentTree);
const prevItems = useTreeStateStore((state) => state.prevItems);
const setPrevItems = useTreeStateStore((state) => state.setPrevItems);

const showDialog = useDialogStore((state) => state.showDialog);
const showInputDialog = useInputDialogStore((state) => state.showDialog);

const { handleError } = useError();
const {
saveItemsDb,
saveTreesListDb,
saveCurrentTreeNameDb,
loadTreesListFromDb,
loadTreeNameFromDb,
loadAllTreesDataFromDb,
deleteTreeFromDb,
} = useDatabase();
const { copyTreeDataToIdbFromDb,
loadCurrentTreeDataFromIdb,
loadTreesListFromIdb,
saveItemsIdb,
saveTreesListIdb,
saveCurrentTreeNameIdb,
deleteTreeIdb
} = useIndexedDb();
const { deleteFile } = useAttachedFile();

// ツリーリストをDBから取得する ---------------------------------------------------------------------------
const loadTreesList = async () => {
try {
if (!uid) {
return;
}
if (!isLoading) setIsLoading(true);
const treesListFromDb = await loadTreesListFromDb(uid);
let missingTrees: string[] = [];
if (treesListFromDb) {
const data: string[] = treesListFromDb;
let treesListAccumulator: TreesList = [];
// 反復してツリー名をDBから取得
const promises = data.map(async (treeId) => {
const treeTitle = await loadTreeNameFromDb(treeId);
if (treeTitle) {
treesListAccumulator = [...treesListAccumulator, { id: treeId, name: treeTitle }];
} else {
console.log('ツリー名が取得できませんでした。' + treeId + 'のツリーは削除されている可能性があります。');
missingTrees = missingTrees ? [...missingTrees, treeId] : [treeId];
}
});
await Promise.all(promises);
// DBの順序に基づいてtreesListAccumulatorを並び替え
const orderedTreesList = data
.map((treeId) => treesListAccumulator.find((t) => t.id === treeId))
.filter((t): t is TreesListItem => t !== undefined);
setTreesList(orderedTreesList);
setIsLoading(false);
} else {
setTreesList([]);
console.log('ツリーリストが見つかりませんでした。');
setIsLoading(false);
}

// 削除されたツリーを通知
if (missingTrees && missingTrees.length > 0) {
await showDialog('1つ以上のツリーが他のユーザーまたはシステムによって削除されました。\n\n' + missingTrees, 'Information');
}
} catch (error) {
handleError('ツリーリストの取得に失敗しました。\n\n' + error);
}
};

// ターゲットIDのitems、name、membersをDBからロードする ---------------------------------------------------------------------------
const loadCurrentTreeData = async (targetTree: UniqueIdentifier) => {
if (!isLoading) setIsLoading(true);
// デバウンスで前のツリーの状態変更が残っていたら保存
if (prevCurrentTree && prevCurrentTree !== targetTree && prevItems.length !== 0 && prevItems !== items) {
await saveItemsIdb(prevItems, prevCurrentTree);
await saveItemsDb(prevItems, prevCurrentTree);
setPrevItems(items);
}

try {
if (!uid) {
Expand All @@ -132,8 +75,6 @@ export const useTreeManagement = () => {
members.push({ uid: member, email: treeData.membersV2[member] });
}
setCurrentTreeMembers(members);
setPrevItems([]);
setPrevCurrentTree(targetTree);
setItems(treeData.items);
}

Expand Down Expand Up @@ -170,8 +111,6 @@ export const useTreeManagement = () => {
setCurrentTree(null);
setCurrentTreeName(null);
setCurrentTreeMembers(null);
setPrevCurrentTree(null);
setPrevItems([]);
setItems([]);
setIsAccordionExpanded(false);

Expand Down Expand Up @@ -679,8 +618,6 @@ export const useTreeManagement = () => {
setCurrentTree(null);
setCurrentTreeName(null);
setCurrentTreeMembers(null);
setPrevCurrentTree(null);
setPrevItems([]);
setItems([]);
setIsAccordionExpanded(false);
await deleteTreeIdb(currentTree);
Expand Down Expand Up @@ -711,7 +648,6 @@ export const useTreeManagement = () => {
handleAddUserToTree,
handleDeleteUserFromTree,
handleDeleteTree,
loadTreesList,
loadCurrentTreeData,
};
};

0 comments on commit 4f24f6c

Please sign in to comment.