feature/IO-3291-Tasks-Notifications: Checkpoint

This commit is contained in:
Dave Richer
2025-07-10 13:18:01 -04:00
parent 79e379b61a
commit 1127864ba9
10 changed files with 749 additions and 470 deletions

View File

@@ -342,7 +342,11 @@ function Header(props) {
</div>
)}
<div ref={taskCenterRef}>
<TaskCenterContainer visible={taskCenterVisible} onClose={() => setTaskCenterVisible(false)} />
<TaskCenterContainer
incompleteTaskCount={incompleteTaskCount}
visible={taskCenterVisible}
onClose={() => setTaskCenterVisible(false)}
/>
</div>
</Layout.Header>
);

View File

@@ -13,7 +13,7 @@ import {
} from "@ant-design/icons";
const TaskCenterComponent = forwardRef(
({ visible, tasks, loading, error, onTaskClick, onLoadMore, hasMore, createNewTask }, ref) => {
({ visible, tasks, loading, error, onTaskClick, onLoadMore, hasMore, createNewTask, incompleteTaskCount }, ref) => {
const { t } = useTranslation();
const virtuosoRef = useRef(null);
@@ -56,11 +56,17 @@ const TaskCenterComponent = forwardRef(
const getPriorityColor = (priority) => priorityColors[priority] || null;
const groupContent = (groupIndex) => {
const { label } = groups[groupIndex];
const { label, tasks } = groups[groupIndex];
let displayCount = tasks.length;
if (label === t("tasks.labels.no_due_date")) {
displayCount =
incompleteTaskCount -
groups.reduce((sum, group, idx) => (idx !== groupIndex ? sum + group.tasks.length : sum), 0);
}
return (
<div className="section-title">
{sectionIcons[label]}
{label} ({groups[groupIndex].tasks.length})
{label} ({displayCount})
</div>
);
};
@@ -112,9 +118,9 @@ const TaskCenterComponent = forwardRef(
return (
<div className={`task-center ${visible ? "visible" : ""}`} ref={ref}>
<div className="task-header">
<h3>
{t("tasks.labels.my_tasks_center")} ({tasks.length})
</h3>
<Badge count={incompleteTaskCount} size="medium" offset={[13, -5]}>
<h3>{t("tasks.labels.my_tasks_center")}</h3>
</Badge>
<div className="task-header-actions">
<Button className="create-task-button" type="link" icon={<PlusCircleOutlined />} onClick={createNewTask} />
{loading && <Spin spinning={loading} size="small" />}

View File

@@ -10,7 +10,7 @@ import { setModalContext } from "../../redux/modals/modals.actions";
import { QUERY_TASKS_NO_DUE_DATE_PAGINATED, QUERY_TASKS_WITH_DUE_DATES } from "../../graphql/tasks.queries";
const POLL_INTERVAL = 60 * 1000; // milliseconds
const LIMIT = 50; // Tasks per page for no-due-date tasks
const LIMIT = 5; // Tasks per page for no-due-date tasks
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -21,7 +21,14 @@ const mapDispatchToProps = (dispatch) => ({
setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
});
const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskUpsertContext }) => {
const TaskCenterContainer = ({
visible,
onClose,
bodyshop,
currentUser,
setTaskUpsertContext,
incompleteTaskCount
}) => {
const [tasks, setTasks] = useState([]);
const { isConnected } = useSocket();
const isEmployee = useIsEmployee(bodyshop, currentUser);
@@ -123,6 +130,7 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
onLoadMore={handleLoadMore}
hasMore={hasMore}
createNewTask={createNewTask}
incompleteTaskCount={incompleteTaskCount}
/>
);
};

View File

@@ -54,8 +54,8 @@ export function TaskListContainer({
bodyshop: bodyshop.id,
[relationshipType]: relationshipId,
deleted: deleted === "true",
completed: completed === "true", //TODO: Find where mine is set.
assigned_to: onlyMine ? bodyshop?.employees?.find((e) => e.user_email === currentUser.email)?.id : undefined, // replace currentUserID with the actual ID of the current user
completed: completed === "true",
assigned_to: onlyMine ? bodyshop?.employees?.find((e) => e.user_email === currentUser.email)?.id : undefined,
offset: page ? (page - 1) * pageLimit : 0,
limit: pageLimit,
order: [