Skip to content

Commit

Permalink
Merge branch 'test'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jun-Murakami committed May 6, 2024
2 parents 9af19a7 + bfe0550 commit a9c34f2
Show file tree
Hide file tree
Showing 23 changed files with 1,044 additions and 248 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "com.tasktrees.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 4
versionName "1.1.4"
versionCode 5
versionName "1.2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
81 changes: 81 additions & 0 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ exports.addUserToTree = functions.https.onCall(async (data: { email: string; tre
return currentMembers;
}
});
const treeMembersRefV2 = admin.database().ref(`trees/${treeId}/membersV2`);
await treeMembersRefV2.transaction((currentMembers: { [key: string]: string | boolean } | null) => {
if (currentMembers === null) {
const newMembers: { [key: string]: string } = {};
newMembers[userId] = email; // 新しいメンバーとして追加
return newMembers;
} else {
if (!Object.prototype.hasOwnProperty.call(currentMembers, userId)) {
currentMembers[userId] = email; // メンバーが存在しなければ追加
}
return currentMembers;
}
});

// users/$userId/treeListにtreeIdを追加
const userTreeListRef = admin.database().ref(`users/${userId}/treeList`);
Expand Down Expand Up @@ -138,6 +151,19 @@ exports.removeUserFromTree = functions.https.onCall(async (data: { treeId: strin
}
}
});
const treeMembersRefV2 = admin.database().ref(`trees/${treeId}/membersV2`);
await treeMembersRefV2.transaction((currentMembers: { [key: string]: string } | null) => {
if (currentMembers === null) {
return currentMembers; // 何もしない
} else {
if (Object.prototype.hasOwnProperty.call(currentMembers, userId)) {
delete currentMembers[userId]; // userIdをキーとして持つプロパティを削除
return currentMembers;
} else {
return currentMembers; // ユーザーが見つからない場合は何もしない
}
}
});

// users/$userId/treeListからtreeIdを削除
const userTreeListRef = admin.database().ref(`users/${userId}/treeList`);
Expand Down Expand Up @@ -187,10 +213,26 @@ exports.createNewTree = functions.https.onCall(async (data: { items: ServerTreeI
const db = admin.database();
const treesRef = db.ref('trees');
const newTreeRef = treesRef.push();
const emails = await Promise.all(
Object.keys(members).map(async (uid) => {
const userRecord = await admin.auth().getUser(uid);
return userRecord.email;
})
);
const membersV2: { [key: string]: string } = {};
Object.keys(members).forEach((uid, index) => {
const email = emails[index];
if (email) {
membersV2[uid] = email;
} else {
throw new Error('Email not found for UID: ' + uid);
}
});
await newTreeRef.set({
items: items,
name: name,
members: members,
membersV2: membersV2,
});
return newTreeRef.key;
} catch (error) {
Expand All @@ -217,4 +259,43 @@ exports.copyFileInStorage = functions.https.onCall(async (data: { sourcePath: st
console.error('Error copying file:', error);
throw new functions.https.HttpsError('unknown', 'Failed to copy file');
}
});

// 指定されたuidリストを指定されたタイムスタンプで更新
exports.updateTimestamps = functions.https.onCall(async (data: { uids: string[], timestamp: number }) => {
const { uids, timestamp } = data;
if (!uids || !Array.isArray(uids) || !timestamp) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with valid "uids" and "timestamp".');
}
try {
const db = admin.database();
await Promise.all(
uids.map(async (uid) => {
const userRef = db.ref(`users/${uid}`);
await userRef.update({ timestampV2: timestamp });
await userRef.update({ timestamp: timestamp });
})
);
return { success: true };
} catch (error) {
console.error('Error updating timestamps:', error);
throw new functions.https.HttpsError('unknown', 'Failed to update timestamps');
}
});

// 指定されたツリーのタイムスタンプを更新
exports.updateTreeTimestamp = functions.https.onCall(async (data: { treeId: string, timestamp: number }) => {
const { treeId, timestamp } = data;
if (!treeId || !timestamp) {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with valid "treeId" and "timestamp".');
}
try {
const db = admin.database();
const treeRef = db.ref(`trees/${treeId}`);
await treeRef.update({ timestamp: timestamp });
return { success: true };
} catch (error) {
console.error('Error updating tree timestamp:', error);
throw new functions.https.HttpsError('unknown', 'Failed to update tree timestamp');
}
});
21 changes: 19 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tasktree-s",
"private": true,
"version": "1.1.2",
"version": "1.2.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down Expand Up @@ -29,6 +29,8 @@
"@fontsource/m-plus-1p": "^5.0.18",
"@mui/icons-material": "^5.15.15",
"@mui/material": "^5.15.15",
"dexie": "^4.0.4",
"dexie-react-hooks": "^1.1.7",
"firebase": "^10.6.0",
"immer": "^10.0.4",
"lodash": "^4.17.21",
Expand Down
6 changes: 3 additions & 3 deletions src/components/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function HomePage() {
<>
<TreeSettingsAccordion />
<Box
sx={{ maxWidth: '900px', width: '100%', marginX: 'auto', mb: isQuickMemoExpanded ? 30 : 8 }}
sx={{ maxWidth: '900px', width: '100%', marginX: 'auto', mb: isQuickMemoExpanded ? 50 : 8 }}
id='tree-container'
>
<Box
Expand Down Expand Up @@ -219,10 +219,10 @@ export function HomePage() {
Appleでログイン
</Button>
<Button
onClick={() => {
onClick={async () => {
setIsOffline(true);
setIsLoggedIn(true);
handleCreateOfflineTree();
await handleCreateOfflineTree();
}}
variant='contained'
sx={{ textTransform: 'none' }}
Expand Down
18 changes: 18 additions & 0 deletions src/components/QuickMemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import DriveFileRenameOutlineIcon from '@mui/icons-material/DriveFileRenameOutline';
import SaveAsIcon from '@mui/icons-material/SaveAs';
import ClearIcon from '@mui/icons-material/Clear';
import { useAppStateStore } from '../store/appStateStore';

export const QuickMemo = () => {
Expand Down Expand Up @@ -46,6 +47,7 @@ export const QuickMemo = () => {

// コンポーネントのアンマウント時にイベントリスナーを削除
return () => window.removeEventListener('resize', handleResize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
Expand Down Expand Up @@ -167,6 +169,22 @@ export const QuickMemo = () => {
<SaveAsIcon />
</IconButton>
)}
{isQuickMemoExpanded && quickMemoText && quickMemoText !== '' && (
<IconButton
sx={{
position: 'absolute',
color: theme.palette.grey[500],
bottom:
windowHeight < 600 || isMobile
? 'calc(env(safe-area-inset-bottom) + 125px)'
: 'calc(env(safe-area-inset-bottom) + 318px)',
right: 15,
}}
onClick={() => setQuickMemoText('')}
>
<ClearIcon />
</IconButton>
)}
</AccordionDetails>
</Accordion>
</Box>
Expand Down
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
13 changes: 7 additions & 6 deletions src/components/SortableList/SortableList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { arrayMove, SortableContext } from '@dnd-kit/sortable';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import { useTheme } from '@mui/material/styles';
import { useTreeStateStore } from '../../store/treeStateStore';
import { useDatabase } from '../../hooks/useDatabase';
import { useTreeManagement } from '../../hooks/useTreeManagement';
import { SortableSource } from './SortableSource';
import { SortableItem } from './SortableItem';

Expand All @@ -17,10 +17,11 @@ interface SortableListProps {
export const SortableList: FC<SortableListProps> = ({ handleListClick, setDrawerState }) => {
const treesList = useTreeStateStore((state) => state.treesList);
const setTreesList = useTreeStateStore((state) => state.setTreesList);
const searchResults = useTreeStateStore((state) => state.searchResults);

const [activeId, setActiveId] = useState<number | null>(null);

const { saveTreesListDb } = useDatabase();
const { handleSaveTreesList } = useTreeManagement();

const isPreviewMode = false;
const activeItem = treesList.find((item) => item.id === activeId?.toString());
Expand All @@ -35,7 +36,7 @@ export const SortableList: FC<SortableListProps> = ({ handleListClick, setDrawer
onDragStart={(event) => {
setActiveId(event.active.id as number);
}}
onDragEnd={(event) => {
onDragEnd={async (event) => {
setActiveId(null);
const { active, over } = event;
if (over == null || active.id === over.id) {
Expand All @@ -45,11 +46,11 @@ export const SortableList: FC<SortableListProps> = ({ handleListClick, setDrawer
const newIndex = treesList.findIndex((item) => item.id === over.id);
const newItems = arrayMove(treesList, oldIndex, newIndex);
setTreesList(newItems);
saveTreesListDb(newItems);
await handleSaveTreesList(newItems);
}}
>
<SortableContext items={treesList}>
{treesList.map((item) => (
<SortableContext items={searchResults}>
{searchResults.map((item) => (
<SortableItem
key={item.id}
isPreviewMode={isPreviewMode}
Expand Down
5 changes: 1 addition & 4 deletions src/components/SortableTree/MenuItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,6 @@ export function MenuItemsAttachedFile({ attachedFile }: MenuItemsAttachedFilePro

const anchorElParent = useRef<HTMLButtonElement>(null);
const prevAttachedFileRef = useRef<string | null>(null);
const currentTreeRef = useRef<UniqueIdentifier | null>(null);

const theme = useTheme();

Expand All @@ -508,7 +507,7 @@ export function MenuItemsAttachedFile({ attachedFile }: MenuItemsAttachedFilePro
};

useEffect(() => {
if (prevAttachedFileRef.current !== attachedFile || currentTreeRef.current !== currentTree) {
if (prevAttachedFileRef.current !== attachedFile) {
if (attachedFile?.match(/\.(jpg|jpeg|png|gif|svg|webp|tif|tiff|bmp|ico|cur)$/i) && currentTree) {
const storage = getStorage();
const imageRef = ref(storage, `trees/${currentTree}/${attachedFile}`);
Expand All @@ -525,8 +524,6 @@ export function MenuItemsAttachedFile({ attachedFile }: MenuItemsAttachedFilePro
}
// 現在のattachedFileを記録
prevAttachedFileRef.current = attachedFile;
// 現在のcurrentTreeを記録
currentTreeRef.current = currentTree;
}, [attachedFile, currentTree]);

return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/TreeSettingsAccordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ export function TreeSettingsAccordion() {
onClick={(e) => e.stopPropagation()}
onCompositionStart={() => setIsComposing(true)}
onCompositionEnd={() => setIsComposing(false)}
onKeyDown={(e) => {
onKeyDown={async (e) => {
if (e.key === 'Enter' && !isComposing) {
e.preventDefault(); // エンターキーのデフォルト動作を防ぐ
if (editedTreeName && editedTreeName !== '') {
handleTreeNameSubmit(editedTreeName);
await handleTreeNameSubmit(editedTreeName);
}
setIsAccordionExpanded(false);
}
Expand Down
14 changes: 8 additions & 6 deletions src/hooks/useAppStateManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useAppStateManagement = () => {
const setDarkMode = useAppStateStore((state) => state.setDarkMode);
const setHideDoneItems = useAppStateStore((state) => state.setHideDoneItems);
const setQuickMemoText = useAppStateStore((state) => state.setQuickMemoText);
const setIsLoadedMemoFromDb = useAppStateStore((state) => state.setIsLoadedMemoFromDb);

const { saveTimeStampDb } = useDatabase();
// エラーハンドリング
Expand Down Expand Up @@ -53,6 +54,7 @@ export const useAppStateManagement = () => {
const data = snapshot.val();
if (typeof data === 'string') {
// クイックメモの内容をセット
setIsLoadedMemoFromDb(true);
setQuickMemoText(data);
}
}
Expand All @@ -63,29 +65,29 @@ export const useAppStateManagement = () => {
};

// ダークモードと完了済みアイテムの非表示設定を保存 ------------------------------------------------
const saveAppSettingsDb = (darkModeNew: boolean, hideDoneItemsNew: boolean) => {
const saveAppSettingsDb = async (darkModeNew: boolean, hideDoneItemsNew: boolean) => {
const db = getDatabase();
if (!uid || !db) {
return;
}
try {
const userSettingsRef = ref(db, `users/${uid}/settings`);
saveTimeStampDb();
set(userSettingsRef, { darkMode: darkModeNew, hideDoneItems: hideDoneItemsNew });
await set(userSettingsRef, { darkMode: darkModeNew, hideDoneItems: hideDoneItemsNew });
await saveTimeStampDb(null);
} catch (error) {
handleError(error);
}
}

// クイックメモをデータベースに保存する関数 ---------------------------------------------------------------------------
const saveQuickMemoDb = (quickMemoText: string) => {
const saveQuickMemoDb = async (quickMemoText: string) => {
if (!uid) {
return;
}
try {
const quickMemoRef = ref(getDatabase(), `users/${uid}/quickMemo`);
saveTimeStampDb();
set(quickMemoRef, quickMemoText);
await set(quickMemoRef, quickMemoText);
await saveTimeStampDb(null);
} catch (error) {
handleError('クイックメモの変更をデータベースに保存できませんでした。\n\n' + error);
}
Expand Down
Loading

0 comments on commit a9c34f2

Please sign in to comment.