Skip to content

Commit 8094040

Browse files
authored
feat/FE: add websocket for CRUD tasks (#16)
* add ws for create task * add ws for update task status * add ws for update tasks * fix cicd
1 parent 5fdf0b9 commit 8094040

File tree

16 files changed

+339
-195
lines changed

16 files changed

+339
-195
lines changed

.github/workflows/frontend-ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ jobs:
5050
- name: Build & Deploy
5151
run: |
5252
npm run build
53-
npx vercel --prod --yes --token=${{ secrets.TRELLO_FRONTEND_VERCEL_TOKEN }}
54-
env:
55-
VERCEL_ORG_ID: ${{ vars.TRELLO_FRONTEND_VERCEL_ORG_ID }}
56-
VERCEL_PROJECT_ID: ${{ vars.TRELLO_FRONTEND_VERCEL_PROJECT_ID }}
57-
VITE_TRELLO_LIKE_API_URL: ${{ vars.VITE_TRELLO_LIKE_API_URL }}
53+
# npx vercel --prod --yes --token=${{ secrets.TRELLO_FRONTEND_VERCEL_TOKEN }}
54+
# env:
55+
# VERCEL_ORG_ID: ${{ vars.TRELLO_FRONTEND_VERCEL_ORG_ID }}
56+
# VERCEL_PROJECT_ID: ${{ vars.TRELLO_FRONTEND_VERCEL_PROJECT_ID }}
57+
# VITE_TRELLO_LIKE_API_URL: ${{ vars.VITE_TRELLO_LIKE_API_URL }}

backend/conf/application.conf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,15 @@ linkpreview.api.key = ${?LINK_PREVIEW_API_KEY}
9393
# Data seeder configuration
9494
seeder {
9595
numUsers = 30
96+
numUsers = ${?SEEDER_NUM_USERS}
9697
numWorkspaces = 4
98+
numWorkspaces = ${?SEEDER_NUM_WORKSPACES}
9799
projectsPerWorkspaceMin = 1
100+
projectsPerWorkspaceMin = ${?SEEDER_PROJECTS_PER_WORKSPACE_MIN}
98101
projectsPerWorkspaceMax = 3
99-
totalTasksPerProject = 60000
102+
projectsPerWorkspaceMax = ${?SEEDER_PROJECTS_PER_WORKSPACE_MAX}
103+
totalTasksPerProject = 10000
104+
totalTasksPerProject = ${?SEEDER_TOTAL_TASKS_PER_PROJECT}
100105
taskBatch = 3000
106+
taskBatch = ${?SEEDER_TASK_BATCH}
101107
}

frontend/src/components/board/ArchivedItemsModal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const ArchivedItemsModal: React.FC<ArchivedItemsModalProps> = ({
2828
const modalRef = useRef<HTMLDivElement>(null);
2929

3030
const currentItems = currentView === 'tasks' ? archivedTasks : archivedColumns;
31+
console.log("Rendering ArchivedItemsModal, currentView:", currentView);
3132

3233
return (
3334
<div
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Lock, Unlock } from "lucide-react";
2+
import type React from "react";
3+
4+
interface BoardClosedBannerProps {
5+
status?: string;
6+
handleReopenBoard: () => void;
7+
}
8+
9+
const BoardClosedBanner: React.FC<BoardClosedBannerProps> = ({ status, handleReopenBoard }) => {
10+
return (
11+
<>
12+
{status && status === 'completed' ? (
13+
<div className='bg-red-500 text-white px-4 py-3 flex items-center justify-between'>
14+
<div className='flex items-center gap-2'>
15+
<Lock size={18} />
16+
<span className='font-medium'>
17+
This board is closed. Reopen the board to make changes.
18+
</span>
19+
</div>
20+
<button
21+
onClick={handleReopenBoard}
22+
className='bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-md flex items-center gap-2 transition-colors font-medium'
23+
>
24+
<Unlock size={16} />
25+
Reopen board
26+
</button>
27+
</div>
28+
) : null}
29+
</>
30+
)
31+
}
32+
33+
export default BoardClosedBanner

frontend/src/components/board/BoardNavbar.tsx

Lines changed: 87 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { selectArchivedColumns } from '@/store/selectors/columnsSelector';
1212
import { selectArchivedTasks } from '@/store/selectors/tasksSelectors';
1313
import { fetchArchivedColumnsThunk } from '@/store/thunks/columnsThunks';
1414
import { fetchArchivedTasksThunk } from '@/store/thunks/tasksThunks';
15-
import { taskRestored } from '@/store/slices/archiveTasksSlice';
15+
import { archivedTaskRestored } from '@/store/slices/archiveTasksSlice';
1616
import { columnDeleted } from '@/store/slices/archiveColumnsSlice';
1717

1818
// const menuItems = [
@@ -68,7 +68,7 @@ const BoardNavbar: React.FC<BoardNavbarProps> = ({
6868
};
6969

7070
const confirmCloseBoard = async () => {
71-
if(!boardId) return;
71+
if (!boardId) return;
7272
await completedBoard(Number(boardId));
7373
handleCloseMenu();
7474
navigate(`/workspace/boards/${wsId}`)
@@ -91,7 +91,7 @@ const BoardNavbar: React.FC<BoardNavbarProps> = ({
9191
const handleRestoreTask = async (taskId: number) => {
9292
try {
9393
const result = await taskService.restoreTask(taskId);
94-
dispatch(taskRestored(taskId));
94+
dispatch(archivedTaskRestored(taskId));
9595
notify.success(result.message);
9696
} catch (error: any) {
9797
notify.error(error.response?.data?.message);
@@ -160,24 +160,24 @@ const BoardNavbar: React.FC<BoardNavbarProps> = ({
160160
{/* Menu */}
161161
{
162162
!showArchivedItems ?
163-
<div className="absolute right-0 top-10 w-80 bg-[#2c3e50] rounded-lg shadow-xl z-50 border border-gray-600">
164-
{/* Menu Header */}
165-
<div className="flex items-center justify-between p-3 border-b border-gray-600">
166-
<span className="text-white font-medium text-sm">Menu</span>
167-
<button
168-
onClick={() => setShowMenu(false)}
169-
className="text-gray-400 hover:text-white transition-colors"
170-
>
171-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
172-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
173-
</svg>
174-
</button>
175-
</div>
163+
<div className="absolute right-0 top-10 w-80 bg-[#2c3e50] rounded-lg shadow-xl z-50 border border-gray-600">
164+
{/* Menu Header */}
165+
<div className="flex items-center justify-between p-3 border-b border-gray-600">
166+
<span className="text-white font-medium text-sm">Menu</span>
167+
<button
168+
onClick={() => setShowMenu(false)}
169+
className="text-gray-400 hover:text-white transition-colors"
170+
>
171+
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
172+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
173+
</svg>
174+
</button>
175+
</div>
176176

177-
{/* Menu Content */}
178-
<div className="p-2">
179-
{/* Main Menu Items */}
180-
{/* {menuItems.map((item, index) => (
177+
{/* Menu Content */}
178+
<div className="p-2">
179+
{/* Main Menu Items */}
180+
{/* {menuItems.map((item, index) => (
181181
<button
182182
key={index}
183183
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
@@ -191,27 +191,27 @@ const BoardNavbar: React.FC<BoardNavbarProps> = ({
191191
</button>
192192
))} */}
193193

194-
{/* Divider */}
195-
<div className="border-t border-gray-600 my-2"></div>
194+
{/* Divider */}
195+
<div className="border-t border-gray-600 my-2"></div>
196196

197-
{/* Power-Ups Section */}
198-
<button
199-
onClick={handleArchivedItemsClick}
200-
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
201-
>
202-
<span className="mr-3 text-base text-white"><Folder /></span>
203-
<div className="flex-1">
204-
<div className='text-gray-300'>
205-
Archived items
197+
{/* Power-Ups Section */}
198+
<button
199+
onClick={handleArchivedItemsClick}
200+
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
201+
>
202+
<span className="mr-3 text-base text-white"><Folder /></span>
203+
<div className="flex-1">
204+
<div className='text-gray-300'>
205+
Archived items
206+
</div>
206207
</div>
207-
</div>
208-
</button>
208+
</button>
209209

210-
{/* Divider */}
211-
<div className="border-t border-gray-600 my-2"></div>
210+
{/* Divider */}
211+
<div className="border-t border-gray-600 my-2"></div>
212212

213-
{/* More Items */}
214-
{/* {moreItems.map((item, index) => (
213+
{/* More Items */}
214+
{/* {moreItems.map((item, index) => (
215215
<button
216216
key={index}
217217
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
@@ -224,64 +224,64 @@ const BoardNavbar: React.FC<BoardNavbarProps> = ({
224224
</div>
225225
</button>
226226
))} */}
227-
{/* Close Board Item - Separate with relative positioning for popup */}
228-
<div className="relative">
229-
<button
230-
onClick={() => setShowCloseConfirm(true)}
231-
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
232-
>
233-
<span className="mr-3 text-base text-white"><X /></span>
234-
<div className="flex-1">
235-
<div className="text-red-400">
236-
Close board
227+
{/* Close Board Item - Separate with relative positioning for popup */}
228+
<div className="relative">
229+
<button
230+
onClick={() => setShowCloseConfirm(true)}
231+
className="w-full flex items-center px-3 py-2 text-sm hover:bg-[#34495e] transition-colors text-left"
232+
>
233+
<span className="mr-3 text-base text-white"><X /></span>
234+
<div className="flex-1">
235+
<div className="text-red-400">
236+
Close board
237+
</div>
237238
</div>
238-
</div>
239-
</button>
239+
</button>
240240

241-
{/* Close Board Confirmation Popup - Positioned above the button */}
242-
{showCloseConfirm && (
243-
<>
244-
{/* Confirmation Popup */}
245-
<div className="absolute bottom-full right-0 bg-[#1a1a1a] rounded p-3">
246-
<div className="flex items-center justify-between pb-2 border-b border-gray-600">
247-
<h3 className="text-white font-semibold text-sm">Close board?</h3>
241+
{/* Close Board Confirmation Popup - Positioned above the button */}
242+
{showCloseConfirm && (
243+
<>
244+
{/* Confirmation Popup */}
245+
<div className="absolute bottom-full right-0 bg-[#1a1a1a] rounded p-3">
246+
<div className="flex items-center justify-between pb-2 border-b border-gray-600">
247+
<h3 className="text-white font-semibold text-sm">Close board?</h3>
248+
<button
249+
onClick={cancelCloseBoard}
250+
className="text-gray-400 hover:text-white transition-colors rounded"
251+
>
252+
<X className="w-4 h-4 cursor-pointer" />
253+
</button>
254+
</div>
255+
<p className="text-gray-300 text-xs mb-3 pt-2 leading-relaxed">
256+
You can find and reopen closed boards at the bottom of{' '}
257+
<span className="text-blue-400 underline cursor-pointer">your boards page</span>.
258+
</p>
248259
<button
249-
onClick={cancelCloseBoard}
250-
className="text-gray-400 hover:text-white transition-colors rounded"
260+
onClick={confirmCloseBoard}
261+
className="w-full bg-red-500 hover:bg-red-600 text-white py-2 rounded text-sm font-medium transition-colors"
251262
>
252-
<X className="w-4 h-4 cursor-pointer" />
263+
Close
253264
</button>
254265
</div>
255-
<p className="text-gray-300 text-xs mb-3 pt-2 leading-relaxed">
256-
You can find and reopen closed boards at the bottom of{' '}
257-
<span className="text-blue-400 underline cursor-pointer">your boards page</span>.
258-
</p>
259-
<button
260-
onClick={confirmCloseBoard}
261-
className="w-full bg-red-500 hover:bg-red-600 text-white py-2 rounded text-sm font-medium transition-colors"
262-
>
263-
Close
264-
</button>
265-
</div>
266-
</>
267-
)}
266+
</>
267+
)}
268+
</div>
268269
</div>
269270
</div>
270-
</div>
271-
:
272-
<>
273-
{/* Archived Items Modal */}
274-
<ArchivedItemsModal
275-
onClose={handleCloseMenu}
276-
onBack={handleBackToMenu}
277-
archivedTasks={archivedTasks}
278-
archivedColumns={archivedColumns}
279-
onRestoreTask={handleRestoreTask}
280-
onRestoreColumn={handleRestoreColumn}
281-
onDeleteTask={handleDeleteTask}
282-
onDeleteColumn={handleDeleteColumn}
283-
/>
284-
</>
271+
:
272+
<>
273+
{/* Archived Items Modal */}
274+
<ArchivedItemsModal
275+
onClose={handleCloseMenu}
276+
onBack={handleBackToMenu}
277+
archivedTasks={archivedTasks}
278+
archivedColumns={archivedColumns}
279+
onRestoreTask={handleRestoreTask}
280+
onRestoreColumn={handleRestoreColumn}
281+
onDeleteTask={handleDeleteTask}
282+
onDeleteColumn={handleDeleteColumn}
283+
/>
284+
</>
285285
}
286286

287287
</>

frontend/src/components/board/DraggableItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const DraggableItem: React.FC<DraggableItemProps> = ({
4646
transition,
4747
};
4848

49+
console.log("Rendering DraggableItem:", item.id, item.name);
4950
return (
5051
<div
5152
ref={setNodeRef}

frontend/src/components/board/DroppableColumn.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ const DroppableColumnComponent: React.FC<DroppableColumnProps> = ({
8282

8383
const itemIds = useMemo(() => items.map(item => item.id), [items]);
8484

85+
console.log('Rendering DroppableColumn:', column.id, column.name);
86+
8587
useEffect(() => {
8688
if (isAddingCard && inputRef.current) {
8789
inputRef.current.focus();

frontend/src/components/board/TaskDetailModal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
4242
// }
4343
// };
4444

45-
const fetchTaskDetail = async (taskId: number) => {
45+
const fetchTaskDetail = async () => {
4646
setIsLoading(true);
4747
try {
4848
const response = await taskService.getTaskDetail(itemId);
@@ -56,9 +56,11 @@ const TaskDetailModal: React.FC<TaskModalProps> = ({
5656
}
5757
}
5858

59+
console.log("Rendering TaskDetailModal for itemId:", itemId, item);
60+
5961

6062
useEffect(() => {
61-
fetchTaskDetail(itemId);
63+
fetchTaskDetail();
6264
}, [itemId]);
6365

6466
return (

frontend/src/main.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import './index.css';
44
import App from './App.tsx';
55

66
createRoot(document.getElementById('root')!).render(
7-
<StrictMode>
7+
// <StrictMode>
88
<App />
9-
</StrictMode>
9+
// </StrictMode>
1010
);

0 commit comments

Comments
 (0)