add popup functionality
This commit is contained in:
parent
1619a7ff7b
commit
ddcb7ea71d
14 changed files with 208 additions and 30 deletions
10
task_management_app/src/app/api/boards/route.ts
Normal file
10
task_management_app/src/app/api/boards/route.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { liveblocksClient } from "@/lib/liveblocksClient";
|
||||||
|
import { Liveblocks } from "@liveblocks/node";
|
||||||
|
import { NextRequest } from "next/server";
|
||||||
|
|
||||||
|
export async function PUT(req: NextRequest){
|
||||||
|
const {id, update} = await req.json();
|
||||||
|
const liveblocks = new Liveblocks({secret: process.env.LIVEBLOCKS_SECRET_KEY as string})
|
||||||
|
await liveblocks.updateRoom(id, update);
|
||||||
|
return Response.json(true)
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Default(){
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import CardModal from '@/components/views/CardModal'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const page = () => {
|
||||||
|
return (
|
||||||
|
<CardModal/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default page
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Default(){
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Default(){
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Default(){
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import React from 'react'
|
||||||
|
import BoardPage from '../../page';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type PageProps ={
|
||||||
|
params:{
|
||||||
|
boardId: string;
|
||||||
|
cardId: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = ({params}: PageProps) => {
|
||||||
|
return (
|
||||||
|
<BoardPage params={params}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default page
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
task_management_app/src/app/boards/[boardId]/defalt.ts
Normal file
3
task_management_app/src/app/boards/[boardId]/defalt.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Default(){
|
||||||
|
return null;
|
||||||
|
}
|
19
task_management_app/src/app/boards/[boardId]/layout.tsx
Normal file
19
task_management_app/src/app/boards/[boardId]/layout.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
|
||||||
|
type PageProps = {
|
||||||
|
children: React.ReactNode,
|
||||||
|
modal: React.ReactNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BoardLayout = ({children, modal}: PageProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{children}
|
||||||
|
{modal}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BoardLayout
|
|
@ -8,6 +8,7 @@ import { IoMdSettings } from "react-icons/io";
|
||||||
import { FormEvent, useState } from 'react';
|
import { FormEvent, useState } from 'react';
|
||||||
import { updateBoard } from '@/app/actions/boardActions';
|
import { updateBoard } from '@/app/actions/boardActions';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { BoardContextProvider } from './BoardContext';
|
||||||
|
|
||||||
|
|
||||||
const Board = ({id, name}: {id:string, name:string}) => {
|
const Board = ({id, name}: {id:string, name:string}) => {
|
||||||
|
@ -30,6 +31,7 @@ const Board = ({id, name}: {id:string, name:string}) => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<BoardContextProvider>
|
||||||
<RoomProvider id={id} initialPresence={{}} initialStorage={
|
<RoomProvider id={id} initialPresence={{}} initialStorage={
|
||||||
{
|
{
|
||||||
columns: new LiveList(),
|
columns: new LiveList(),
|
||||||
|
@ -57,6 +59,7 @@ const Board = ({id, name}: {id:string, name:string}) => {
|
||||||
)}
|
)}
|
||||||
</ClientSideSuspense>
|
</ClientSideSuspense>
|
||||||
</RoomProvider>
|
</RoomProvider>
|
||||||
|
</BoardContextProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
task_management_app/src/components/BoardContext.tsx
Normal file
28
task_management_app/src/components/BoardContext.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import React, { Dispatch, createContext, useState } from "react";
|
||||||
|
|
||||||
|
export type OpenCardId = string | null;
|
||||||
|
|
||||||
|
export type BoardContextProps = {
|
||||||
|
openCard?: OpenCardId;
|
||||||
|
setOpenCard?: Dispatch<React.SetStateAction<OpenCardId>>
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProviderProps = {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const BoardContext = createContext<BoardContextProps>({});
|
||||||
|
|
||||||
|
|
||||||
|
export function BoardContextProvider({children}:ProviderProps){
|
||||||
|
const [openCard, setOpenCard] = useState<OpenCardId>(null);
|
||||||
|
return(
|
||||||
|
<BoardContext.Provider value={{openCard, setOpenCard,}}>
|
||||||
|
{children}
|
||||||
|
</BoardContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
30
task_management_app/src/components/Card.tsx
Normal file
30
task_management_app/src/components/Card.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"use client"
|
||||||
|
import Link from "next/link"
|
||||||
|
import { useParams, useRouter } from "next/navigation"
|
||||||
|
import { useContext, useEffect } from "react";
|
||||||
|
import { BoardContext } from "./BoardContext";
|
||||||
|
|
||||||
|
|
||||||
|
const Card = ({id, name}: {id:string, name:string}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useParams();
|
||||||
|
const {openCard} = useContext(BoardContext);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(params.cardId && !openCard){
|
||||||
|
const {boardId, cardId} = params;
|
||||||
|
router.push(`/boards/${boardId}`);
|
||||||
|
router.push(`/boards/${boardId}/cards/${cardId}`);
|
||||||
|
}
|
||||||
|
}, [params.cardId])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link href={`/boards/${params.boardId}/cards/${id}`} className='border block my-2 p-2 rounded-sm bg-white'>
|
||||||
|
<span>{name}</span>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Card
|
|
@ -4,6 +4,7 @@ import { ReactSortable } from 'react-sortablejs';
|
||||||
import NewCardForm from './forms/NewCardForm';
|
import NewCardForm from './forms/NewCardForm';
|
||||||
import { FormEvent, useState } from 'react';
|
import { FormEvent, useState } from 'react';
|
||||||
import { BsThreeDots } from "react-icons/bs";
|
import { BsThreeDots } from "react-icons/bs";
|
||||||
|
import {default as ColumnCard} from './Card';
|
||||||
|
|
||||||
|
|
||||||
type ColumnProps = {
|
type ColumnProps = {
|
||||||
|
@ -44,6 +45,12 @@ const Column = ({id, name}: ColumnProps) => {
|
||||||
columns.find(c => c.toObject().id === id)?.set('name', newName)
|
columns.find(c => c.toObject().id === id)?.set('name', newName)
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const deleteColumn = useMutation(({storage}, id) => {
|
||||||
|
const columns = storage.get('columns');
|
||||||
|
const columnIndex = columns.findIndex(c => c.toObject().id === id);
|
||||||
|
columns.delete(columnIndex);
|
||||||
|
}, [])
|
||||||
|
|
||||||
const [renameColumn, setRenameColumn] = useState(false);
|
const [renameColumn, setRenameColumn] = useState(false);
|
||||||
function handleRenameColumn(ev: FormEvent){
|
function handleRenameColumn(ev: FormEvent){
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
@ -72,7 +79,7 @@ const Column = ({id, name}: ColumnProps) => {
|
||||||
<input type="text" defaultValue={name} className='border p-2 w-full'/>
|
<input type="text" defaultValue={name} className='border p-2 w-full'/>
|
||||||
<button type="submit" className='w-full mt-2'>Save</button>
|
<button type="submit" className='w-full mt-2'>Save</button>
|
||||||
</form>
|
</form>
|
||||||
<button className='w-full p-2 bg-[tomato] text-white rounded-md font-semibold text-sm'> Delete column</button>
|
<button onClick={() => deleteColumn(id)} className='w-full p-2 bg-[tomato] text-white rounded-md font-semibold text-sm'> Delete column</button>
|
||||||
<button onClick={() => setRenameColumn(false)} className='w-full mt-4 text-xs uppercase font-bold text-gray-500 tracking-wider'>Cancel</button>
|
<button onClick={() => setRenameColumn(false)} className='w-full mt-4 text-xs uppercase font-bold text-gray-500 tracking-wider'>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -82,9 +89,7 @@ const Column = ({id, name}: ColumnProps) => {
|
||||||
<>
|
<>
|
||||||
<ReactSortable list={columnCards} setList={items => setTasksOrderForColumn(items, id)} group="cards" ghostClass='opacity-40' className='min-h-12'>
|
<ReactSortable list={columnCards} setList={items => setTasksOrderForColumn(items, id)} group="cards" ghostClass='opacity-40' className='min-h-12'>
|
||||||
{columnCards.map(card => (
|
{columnCards.map(card => (
|
||||||
<div key={card.id} className='border my-2 p-2 rounded-sm bg-white'>
|
<ColumnCard key={card.id} id={card.id} name={card.name} />
|
||||||
<span>{card.name}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</ReactSortable>
|
</ReactSortable>
|
||||||
</>
|
</>
|
||||||
|
|
34
task_management_app/src/components/views/CardModal.tsx
Normal file
34
task_management_app/src/components/views/CardModal.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useParams, useRouter } from "next/navigation"
|
||||||
|
import { useContext, useEffect } from "react";
|
||||||
|
import { BoardContext, BoardContextProps } from "../BoardContext";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const CardModal = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useParams();
|
||||||
|
const {openCard, setOpenCard} = useContext<BoardContextProps>(BoardContext)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(params.cardId && setOpenCard){
|
||||||
|
setOpenCard(params.cardId.toString());
|
||||||
|
}
|
||||||
|
}, [params])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function handleBackdrop(){
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div onClick={handleBackdrop} className='fixed inset-0 bg-black/80'>
|
||||||
|
<div onClick={ev => ev.stopPropagation()} className='bg-white p-4 mt-8 max-w-xs mx-auto'>test</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardModal
|
Loading…
Add table
Reference in a new issue