From 1dc526648a822092457f5263fcdfb13c533cabbb Mon Sep 17 00:00:00 2001 From: Ken Zou Date: Wed, 19 Aug 2026 21:31:23 -0400 Subject: [PATCH 1/8] refactor: use CSS modules in project report's members and tasks tables --- .../ProjectMemberTable/ProjectMemberTable.jsx | 63 ++++++++++--------- .../Reports/TasksDetail/TasksDetail.jsx | 44 ++++++------- .../Reports/TasksTable/TasksTable.jsx | 28 +++++---- 3 files changed, 69 insertions(+), 66 deletions(-) diff --git a/src/components/Reports/ProjectMemberTable/ProjectMemberTable.jsx b/src/components/Reports/ProjectMemberTable/ProjectMemberTable.jsx index 42e88d551c..655b2664d4 100644 --- a/src/components/Reports/ProjectMemberTable/ProjectMemberTable.jsx +++ b/src/components/Reports/ProjectMemberTable/ProjectMemberTable.jsx @@ -3,9 +3,10 @@ import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import CopyToClipboard from '~/components/common/Clipboard/CopyToClipboard'; import { Stub } from '../../common/Stub'; -import './ProjectMemberTable.module.css'; +import styles from './ProjectMemberTable.module.css'; export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCount, darkMode, counts }) { + console.log('skip:', skip, 'take:', take); const [allMemberList, setAllMemberList] = useState([]); const [activeMemberList, setActiveMemberList] = useState([]); const [memberFilter, setMemberFilter] = useState('active'); @@ -51,11 +52,11 @@ export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCou }, [fetched, members, foundUsers]); const activeMemberTable = activeMemberList.slice(skip, skip + take).map((member, index) => ( -
+
{skip + index + 1}
- +
{window.innerWidth >= 1100 ? `${member.firstName} ${member.lastName}` : `${member.firstName.substring(0, 10)} ${member.lastName.substring(0, 1)}`}
@@ -71,7 +72,7 @@ export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCou
)}
-
+
{member._id}
@@ -79,11 +80,11 @@ export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCou )); const allMemberTable = allMemberList.slice(skip, skip + take).map((member, index) => ( -
+
{skip + index + 1}
- +
{window.innerWidth >= 1100 ? `${member.firstName} ${member.lastName}` : `${member.firstName.substring(0, 10)} ${member.lastName.substring(0, 1)}`}
@@ -99,7 +100,7 @@ export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCou
)}
-
+
{member._id}
@@ -107,31 +108,31 @@ export function ProjectMemberTable({ projectMembers, skip, take, handleMemberCou )); return ( -
-
Members
-
-
{ - const val = e.target.value; - setMemberFilter(val); - handleMemberCount(val === 'all-time' ? allMemberList.length : activeMemberList.length); - }} - > - - - - -
+
+
Members
+
+
{ + const val = e.target.value; + setMemberFilter(val); + handleMemberCount(val === 'all-time' ? allMemberList.length : activeMemberList.length); + } + }> + + + + +
-
-
#
-
Name
-
Active
-
ID
+
+
#
+
Name
+
Active
+
ID
{memberFilter === 'all-time' && allMemberTable.length > 0 && allMemberTable} diff --git a/src/components/Reports/TasksDetail/TasksDetail.jsx b/src/components/Reports/TasksDetail/TasksDetail.jsx index 8f889a245d..30711a72c2 100644 --- a/src/components/Reports/TasksDetail/TasksDetail.jsx +++ b/src/components/Reports/TasksDetail/TasksDetail.jsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import { Button } from 'react-bootstrap'; import Collapse from 'react-bootstrap/Collapse'; import EditTaskModal from '../../Projects/WBS/WBSDetail/EditTask/EditTaskModal'; -import './TasksDetail.module.css'; +import styles from './TasksDetail.module.css'; @@ -77,19 +77,19 @@ export function TasksDetail(props) { const tasksList = filteredTasks.map((task, index) => ( - + {index + 1} - {truncate(task.taskName, 20)} - {task.priority} + {truncate(task.taskName, 20)} + {task.priority} {task.status} - + {task.resources.length <= 2 ? ( task.resources.map((resource) =>
{resource.name}
) ) : ( )} - + {task.resources.length <= 2 ? ( task.resources.map((resource, innerIndex) => ( @@ -102,13 +102,13 @@ export function TasksDetail(props) { )} - + {task.isAssigned ?
Assign
:
Not Assign
} - {task.classification} - {task.estimatedHours.toFixed(2)} - {formatDate(task.startedDatetime)} - {formatDate(task.dueDatetime)} + {task.classification} + {task.estimatedHours.toFixed(2)} + {formatDate(task.startedDatetime)} + {formatDate(task.dueDatetime)} {props.toggleEditTasks && ( -
Total: {tasksList.length}
- - +
Total: {tasksList.length}
+
+ - + - - - - - - - + + + + + + + diff --git a/src/components/Reports/TasksTable/TasksTable.jsx b/src/components/Reports/TasksTable/TasksTable.jsx index 6add0df240..89f83a4a01 100644 --- a/src/components/Reports/TasksTable/TasksTable.jsx +++ b/src/components/Reports/TasksTable/TasksTable.jsx @@ -5,14 +5,16 @@ import { useState, useEffect, useRef } from 'react'; import '../../Teams/Team.module.css'; import 'react-datepicker/dist/react-datepicker.css'; -import './TasksTable.module.css'; +import styles from './TasksTable.module.css'; import Select from 'react-select'; import { Checkbox } from '~/components/common/Checkbox'; import TextSearchBox from '~/components/UserManagement/TextSearchBox'; import { boxStyle, boxStyleDark } from '~/styles'; import { TasksDetail } from '../TasksDetail'; +import { stubArray } from 'lodash'; export function TasksTable({ darkMode, tasks, projectId }) { + console.log(darkMode) const [isActive, setActive] = useState(true); const [isAssigned, setAssigned] = useState(true); const [toggleEditTasks, setToggleEditTasks] = useState(false); @@ -71,63 +73,63 @@ export function TasksTable({ darkMode, tasks, projectId }) { return (
-

Tasks

+

Tasks

-
-
+
+
handleSelectChange(selectedOption, 'classification')} - className="tasks-table-filter-item tasks-table-filter-input" + className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']}`} value={filters.classification ? { value: filters.classification, label: filters.classification } : null} /> handleSelectChange(selectedOption, 'status')} - className="tasks-table-filter-item tasks-table-filter-input" + className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']}`} value={filters.status ? { value: filters.status, label: filters.status } : null} /> { }} /> setActive(!isActive)} id="active_checkbox" - wrapperClassname="tasks-table-filter-item" + wrapperClassname={styles['tasks-table-filter-item']} label="Active" /> setAssigned(!isAssigned)} id="assign_checkbox" - wrapperClassname="tasks-table-filter-item" + wrapperClassname={styles['tasks-table-filter-item']} label="Assign" />
+ @@ -140,8 +140,8 @@ export function TasksDetail(props) { - - + + diff --git a/src/components/Reports/TasksDetail/TasksDetail.module.css b/src/components/Reports/TasksDetail/TasksDetail.module.css index 679dd3959a..6092a7d809 100644 --- a/src/components/Reports/TasksDetail/TasksDetail.module.css +++ b/src/components/Reports/TasksDetail/TasksDetail.module.css @@ -14,17 +14,52 @@ min-width: 800px; /* Minimum width to maintain table layout on smaller screens */ } -.tasks-detail-table th, .tasks-detail-table td { - padding: 5px; - border: 1px solid #ddd; + +.tasks-detail-table th, +.tasks-detail-table td { + padding: 0 16px; + border: none; text-align: left; + vertical-align: middle; } .tasks-detail-table-head { - background-color: #f8f9fa; + background-color: #eee7f8; font-weight: bold; } + +.tasks-detail-table-head tr { + border-bottom: 3px solid #f8f7f8; +} + +.tasks-detail-table-head th { + height: 42px; + padding: 0 16px; + border: none; + text-align: left; + vertical-align: middle; +} + + + +.tasks-detail-table-head th:first-child { + border-radius: 4px 0 0 4px; +} + +.tasks-detail-table-head th:last-child { + border-radius: 0 4px 4px 0; +} + + + + +.tasks-detail-table-row { + border-bottom: 3px solid #f8f7f8; + text-align: left; +} + + .tasks-detail-center-cells { text-align: center; } @@ -46,19 +81,25 @@ color: #fff; } + +.dark-mode-row:hover { + background-color: #111831; + color: #fff; +} + /* Responsive design */ + @media screen and (width <= 1100px) { .collapse-column { display: none; } -} -@media screen and (width <= 1100px) { .tasks-detail-table { min-width: 600px; } - .tasks-detail-table th, .tasks-detail-table td { + .tasks-detail-table th, + .tasks-detail-table td { padding: 5px; font-size: 12px; } @@ -73,7 +114,8 @@ min-width: 400px; } - .tasks-detail-table th, .tasks-detail-table td { + .tasks-detail-table th, + .tasks-detail-table td { padding: 2px; font-size: 10px; } @@ -85,4 +127,4 @@ .tasks-detail-center-cells { font-size: 10px; } -} \ No newline at end of file +} diff --git a/src/components/Reports/TasksTable/TasksTable.jsx b/src/components/Reports/TasksTable/TasksTable.jsx index 89f83a4a01..9cd9854005 100644 --- a/src/components/Reports/TasksTable/TasksTable.jsx +++ b/src/components/Reports/TasksTable/TasksTable.jsx @@ -14,7 +14,6 @@ import { TasksDetail } from '../TasksDetail'; import { stubArray } from 'lodash'; export function TasksTable({ darkMode, tasks, projectId }) { - console.log(darkMode) const [isActive, setActive] = useState(true); const [isAssigned, setAssigned] = useState(true); const [toggleEditTasks, setToggleEditTasks] = useState(false); @@ -82,28 +81,36 @@ export function TasksTable({ darkMode, tasks, projectId }) { options={getUserOptions()} placeholder="Any user" onChange={(selectedOption) => handleSelectChange(selectedOption, 'users')} - className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']}`} + className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']} ${darkMode ? styles['dark-mode-select'] : ''}`} + classNamePrefix="select" + menuPortalTarget={document.body} value={filters.users ? { value: filters.users, label: filters.users } : null} /> handleSelectChange(selectedOption, 'priority')} - className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']}`} + className={`${styles['tasks-table-filter-item']} ${styles['tasks-table-filter-input']} ${darkMode ? styles['dark-mode-select'] : ''}`} + classNamePrefix="select" + menuPortalTarget={document.body} value={filters.priority ? { value: filters.priority, label: filters.priority } : null} />
# TaskPriorityPriority StatusResourcesActiveAssignClassEstimated HoursStart DateEnd DateResourcesActiveAssignClassEstimated HoursStart DateEnd Date Actions
{index + 1} {truncate(task.taskName, 20)} {task.priority}Status Resources ActiveAssignClassAssignClass Estimated Hours Start Date End Date
@@ -517,7 +510,7 @@ function EditTaskModal(props) { rows="2" type="text" className={`task-name border border-dark rounded ${ - darkMode ? 'bg-darkmode-liblack text-light border-0' : '' + darkMode ? `${styles.editTaskTextareaDark} text-light` : '' }`} onChange={e => setTaskName(e.target.value)} onKeyPress={e => setTaskName(e.target.value)} diff --git a/src/components/Projects/WBS/WBSDetail/components/TagsSearch.jsx b/src/components/Projects/WBS/WBSDetail/components/TagsSearch.jsx index 3d14ef2448..2005438468 100644 --- a/src/components/Projects/WBS/WBSDetail/components/TagsSearch.jsx +++ b/src/components/Projects/WBS/WBSDetail/components/TagsSearch.jsx @@ -123,15 +123,15 @@ function TagsSearch(props) { )} {shouldShowDropdown && ( -
    +
      {filteredMembers.map((member, index) => (
    • + key={member._id || member.userID || index} + className={`dropdown-item border-bottom fs-6 w-100 p-1 ${darkMode ? styles.darkDropdownItem : ''}`} + >