From 1619a7ff7b5a9dcd3dcca2067f6eebb4df5d1d48 Mon Sep 17 00:00:00 2001 From: Juthatip McDevitt Date: Wed, 27 Mar 2024 14:42:00 -0500 Subject: [PATCH] added delete board delete column fuctionality and so on --- .../src/app/actions/boardActions.ts | 18 +++++++ .../src/app/boards/[boardId]/page.tsx | 2 +- .../app/boards/[boardId]/settings/page.tsx | 15 +++--- task_management_app/src/components/Board.tsx | 31 +++++++++++- .../src/components/BoardDelete.tsx | 23 +++++++++ task_management_app/src/components/Column.tsx | 48 +++++++++++++++++-- .../src/components/EmailAccessList.tsx | 33 +++++++++++++ .../src/lib/liveblocksClient.ts | 8 +++- 8 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 task_management_app/src/components/BoardDelete.tsx create mode 100644 task_management_app/src/components/EmailAccessList.tsx diff --git a/task_management_app/src/app/actions/boardActions.ts b/task_management_app/src/app/actions/boardActions.ts index f470227..705eb4c 100644 --- a/task_management_app/src/app/actions/boardActions.ts +++ b/task_management_app/src/app/actions/boardActions.ts @@ -35,4 +35,22 @@ export async function addEmailtoBoard(boardId: string, email: string){ usersAccesses[email] = ['room:write']; await liveblocksClient.updateRoom(boardId, {usersAccesses}); return true; +} + +export async function updateBoard(boardId:string, updateData:any){ + const result = await liveblocksClient.updateRoom(boardId, updateData); + return true; +} + +export async function removeEmailFromBoard(boardId:string, email:string){ + const room = await liveblocksClient.getRoom(boardId); + const usersAccesses:any = room.usersAccesses; + usersAccesses[email] = null + await liveblocksClient.updateRoom(boardId, {usersAccesses}); + return true; +} + +export async function deleteBoard(boardId:string){ + await liveblocksClient.deleteRoom(boardId) + return true } \ No newline at end of file diff --git a/task_management_app/src/app/boards/[boardId]/page.tsx b/task_management_app/src/app/boards/[boardId]/page.tsx index 4b11d8c..d117202 100644 --- a/task_management_app/src/app/boards/[boardId]/page.tsx +++ b/task_management_app/src/app/boards/[boardId]/page.tsx @@ -28,7 +28,7 @@ const BoardPage = async (props: PageProps) => { return (
- +
) } diff --git a/task_management_app/src/app/boards/[boardId]/settings/page.tsx b/task_management_app/src/app/boards/[boardId]/settings/page.tsx index 127a1c1..bcd9ab0 100644 --- a/task_management_app/src/app/boards/[boardId]/settings/page.tsx +++ b/task_management_app/src/app/boards/[boardId]/settings/page.tsx @@ -1,4 +1,6 @@ "use server" +import BoardDelete from "@/components/BoardDelete"; +import EmailAccessList from "@/components/EmailAccessList"; import NewUserAccess from "@/components/forms/NewUserAccess"; import { liveblocksClient } from "@/lib/liveblocksClient"; import { getUserEmail } from "@/lib/userClient"; @@ -23,14 +25,13 @@ const page = async ({params}: PageProps) => { return (
- Go back -

Access to {boardInfo.metadata.boardName}:

+
+ Go back + +
+

Access to {boardInfo.metadata.boardName}:

- {Object.keys(boardInfo.usersAccesses).map(email => ( -
- {email} -
- ))} +
diff --git a/task_management_app/src/components/Board.tsx b/task_management_app/src/components/Board.tsx index d047c3f..f5355f1 100644 --- a/task_management_app/src/components/Board.tsx +++ b/task_management_app/src/components/Board.tsx @@ -5,9 +5,29 @@ import { ClientSideSuspense } from '@liveblocks/react'; import Columns from './Columns'; import Link from 'next/link'; import { IoMdSettings } from "react-icons/io"; +import { FormEvent, useState } from 'react'; +import { updateBoard } from '@/app/actions/boardActions'; +import { useRouter } from 'next/navigation'; + + +const Board = ({id, name}: {id:string, name:string}) => { + const [renameBoard, setRenameBoard] = useState(false); + const router = useRouter(); + + async function handleRenameSubmit(ev:FormEvent){ + ev.preventDefault(); + const input = (ev.target as HTMLFormElement).querySelector('input'); + if(input){ + const newBoardName = input?.value; + await updateBoard(id, {metadata: {boardName: newBoardName}}); + input.value = ''; + setRenameBoard(false); + router.refresh(); + } + + } -const Board = ({id, name}: {id: string, name: string}) => { return ( { <>
-

Board: {name}

+ {!renameBoard && ( +

setRenameBoard(true)} className='text-2xl'>Board: {name}

+ )} + {renameBoard && ( +
+ +
+ )}
diff --git a/task_management_app/src/components/BoardDelete.tsx b/task_management_app/src/components/BoardDelete.tsx new file mode 100644 index 0000000..f678797 --- /dev/null +++ b/task_management_app/src/components/BoardDelete.tsx @@ -0,0 +1,23 @@ +"use client" +import { deleteBoard } from "@/app/actions/boardActions" +import { useRouter } from "next/navigation"; + + +const BoardDelete = ({boardId}:{boardId:string}) => { + const router = useRouter(); + async function handleDeleteBoard(){ + await deleteBoard(boardId); + router.push('/'); + } + + + + return ( +
+ +
+ + ) +} + +export default BoardDelete \ No newline at end of file diff --git a/task_management_app/src/components/Column.tsx b/task_management_app/src/components/Column.tsx index eac0ab5..3ece2bb 100644 --- a/task_management_app/src/components/Column.tsx +++ b/task_management_app/src/components/Column.tsx @@ -2,6 +2,8 @@ import { Card, useMutation, useStorage } from '@/app/liveblocks.config'; import { shallow } from '@liveblocks/client'; import { ReactSortable } from 'react-sortablejs'; import NewCardForm from './forms/NewCardForm'; +import { FormEvent, useState } from 'react'; +import { BsThreeDots } from "react-icons/bs"; type ColumnProps = { @@ -35,13 +37,48 @@ const Column = ({id, name}: ColumnProps) => { }) }) - },[]) + }, []); + + const updateColumn = useMutation(({storage}, id, newName) => { + const columns = storage.get('columns'); + columns.find(c => c.toObject().id === id)?.set('name', newName) + }, []); + + const [renameColumn, setRenameColumn] = useState(false); + function handleRenameColumn(ev: FormEvent){ + ev.preventDefault(); + const input = (ev.target as HTMLFormElement).querySelector('input') + if(input){ + const newColumnName = input.value; + updateColumn(id, newColumnName) + setRenameColumn(false); + } + } + return (
-

{name}

- {columnCards && ( + {!renameColumn && ( +
+

{name}

+ +
+ )} + {renameColumn && ( +
+ Edit name: +
+ + +
+ + +
+ + )} + + {!renameColumn && columnCards && ( <> setTasksOrderForColumn(items, id)} group="cards" ghostClass='opacity-40' className='min-h-12'> {columnCards.map(card => ( @@ -52,7 +89,10 @@ const Column = ({id, name}: ColumnProps) => { )} - + {!renameColumn && ( + + )} +
) diff --git a/task_management_app/src/components/EmailAccessList.tsx b/task_management_app/src/components/EmailAccessList.tsx new file mode 100644 index 0000000..5ae7ec0 --- /dev/null +++ b/task_management_app/src/components/EmailAccessList.tsx @@ -0,0 +1,33 @@ +"use client" +import { deleteBoard, removeEmailFromBoard } from "@/app/actions/boardActions"; +import { RoomAccesses } from "@liveblocks/node"; +import { useRouter } from "next/navigation"; +import { IoTrashOutline } from "react-icons/io5"; + + + + +const EmailAccessList = ({boardId, usersAccesses} : {boardId:string ,usersAccesses:RoomAccesses}) => { + const router = useRouter(); + async function handleDelete(emailToDelete: string){ + await removeEmailFromBoard(boardId, emailToDelete) + router.refresh(); + } + + + + return ( +
+ {Object.keys(usersAccesses).map(email => ( +
+ {email} + +
+ ))} +
+ ) +} + +export default EmailAccessList \ No newline at end of file diff --git a/task_management_app/src/lib/liveblocksClient.ts b/task_management_app/src/lib/liveblocksClient.ts index 186888c..776406f 100644 --- a/task_management_app/src/lib/liveblocksClient.ts +++ b/task_management_app/src/lib/liveblocksClient.ts @@ -2,4 +2,10 @@ import { Liveblocks } from "@liveblocks/node"; export const liveblocksClient = new Liveblocks({ secret: process.env.LIVEBLOCKS_SECRET_KEY || '', -}); \ No newline at end of file +}); + +export function getLiveblocksClient(){ + return new Liveblocks({ + secret: process.env.LIVEBLOCKS_SECRET_KEY || '', + }); +} \ No newline at end of file