-
- {t("tasks.labels.my_tasks_center")}
- {loading && }
-
-
-
-
- {showIncompleteOnly ? : }
- toggleIncomplete(checked)} size="small" />
-
-
-
-
+
+
+
+
+
+ {t("notifications.labels.ro-number", {
+ ro_number: task.job?.ro_number || t("general.labels.na")
+ })}
+
+
+ {day(task.created_at).fromNow()}
+
+
+
+ {task.title}
+
-
-
+
);
- }
-);
+ };
+
+ const renderSection = (section, sectionIndex) => (
+
+
+ {section.title}
+
+ {section.data.map((task, index) => renderTask(`${sectionIndex}-${index}`, task))}
+
+ );
+
+ return (
+
+
+
{t("tasks.labels.my_tasks_center")}
+ {loading && }
+
+
renderSection(section, index)}
+ />
+
+ );
+});
TaskCenterComponent.displayName = "TaskCenterComponent";
diff --git a/client/src/components/task-center/task-center.container.jsx b/client/src/components/task-center/task-center.container.jsx
index dad0f97e7..cfecedf75 100644
--- a/client/src/components/task-center/task-center.container.jsx
+++ b/client/src/components/task-center/task-center.container.jsx
@@ -1,15 +1,14 @@
import { useCallback, useEffect, useMemo, useState } from "react";
-import { useMutation, useQuery } from "@apollo/client";
+import { useQuery } from "@apollo/client";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import { useSocket } from "../../contexts/SocketIO/useSocket";
import { useIsEmployee } from "../../utils/useIsEmployee";
-import { useNotification } from "../../contexts/Notifications/notificationContext";
-import { MUTATION_TOGGLE_TASK_COMPLETED, QUERY_MY_TASKS_PAGINATED } from "../../graphql/tasks.queries";
+import { QUERY_MY_TASKS_PAGINATED } from "../../graphql/tasks.queries";
import TaskCenterComponent from "./task-center.component";
import dayjs from "../../utils/day";
-import { setModalContext } from "../../redux/modals/modals.actions"; // Import setModalContext
+import { setModalContext } from "../../redux/modals/modals.actions";
const POLL_INTERVAL = 60; // seconds
@@ -24,20 +23,28 @@ const mapDispatchToProps = (dispatch) => ({
const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskUpsertContext }) => {
const [tasks, setTasks] = useState([]);
- const [showIncompleteOnly, setShowIncompleteOnly] = useState(true);
const [loading, setLoading] = useState(false);
const { isConnected } = useSocket();
const isEmployee = useIsEmployee(bodyshop, currentUser);
- const notification = useNotification();
- const assignedToId = bodyshop?.employees?.find((e) => e.user_email === currentUser.email)?.id;
- const where = useMemo(() => {
- return {
+ // Compute assignedToId with useMemo to ensure stability
+ const assignedToId = useMemo(() => {
+ const employee = bodyshop?.employees?.find((e) => e.user_email === currentUser?.email);
+ if (employee?.id) {
+ console.log("AssignedToId computed:", employee.id); // Debug log
+ return employee.id;
+ }
+ return null;
+ }, [bodyshop, currentUser]);
+
+ const where = useMemo(
+ () => ({
assigned_to: { _eq: assignedToId },
deleted: { _eq: false },
- ...(showIncompleteOnly ? { completed: { _eq: false } } : {})
- };
- }, [assignedToId, showIncompleteOnly]);
+ completed: { _eq: false }
+ }),
+ [assignedToId]
+ );
const {
data,
@@ -50,49 +57,24 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
where,
offset: 0,
limit: 50,
- order: [{ created_at: "desc" }]
+ order: [{ due_date: "asc_nulls_last" }, { created_at: "desc" }]
},
- skip: !bodyshop?.id || !assignedToId || !isEmployee,
+ // Skip query if any required data is missing
+ skip: !bodyshop?.id || !assignedToId || !isEmployee || !currentUser?.email,
fetchPolicy: "cache-and-network",
- pollInterval: isConnected ? 0 : dayjs.duration(POLL_INTERVAL, "seconds").asMilliseconds()
+ pollInterval: isConnected ? 0 : dayjs.duration(POLL_INTERVAL, "seconds").asMilliseconds(),
+ // Log errors for debugging
+ onError: (error) => {
+ console.error("Query error:", error);
+ }
});
- const [toggleTaskCompleted] = useMutation(MUTATION_TOGGLE_TASK_COMPLETED);
-
useEffect(() => {
if (data?.tasks) {
setTasks(data.tasks);
}
}, [data]);
- const handleToggleIncomplete = (val) => {
- setShowIncompleteOnly(val);
- };
-
- const handleMarkAllComplete = async () => {
- setLoading(true);
- try {
- const incompleteTasks = tasks.filter((t) => !t.completed);
- await Promise.all(
- incompleteTasks.map((task) =>
- toggleTaskCompleted({
- variables: {
- id: task.id,
- completed: true,
- completed_at: dayjs().toISOString()
- }
- })
- )
- );
- notification.success({ message: "Tasks marked complete" });
- refetch();
- } catch (err) {
- notification.error({ message: "Failed to mark tasks complete" });
- } finally {
- setLoading(false);
- }
- };
-
const handleTaskClick = useCallback(
(id) => {
const task = tasks.find((t) => t.id === id);
@@ -105,7 +87,7 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
});
}
},
- [tasks, setModalContext]
+ [tasks, setTaskUpsertContext]
);
return (
@@ -114,10 +96,7 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
onClose={onClose}
tasks={tasks}
loading={loading || queryLoading}
- showIncompleteOnly={showIncompleteOnly}
- toggleIncomplete={handleToggleIncomplete}
- markAllComplete={handleMarkAllComplete}
- onTaskClick={handleTaskClick} // Pass the updated handler
+ onTaskClick={handleTaskClick}
/>
);
};
diff --git a/client/src/components/task-center/task-center.styles.scss b/client/src/components/task-center/task-center.styles.scss
index 2970f4b39..0f62c1306 100644
--- a/client/src/components/task-center/task-center.styles.scss
+++ b/client/src/components/task-center/task-center.styles.scss
@@ -18,7 +18,7 @@
}
.task-header {
- padding: 4px 16px;
+ padding: 8px 16px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
@@ -30,57 +30,20 @@
font-size: 14px;
color: rgba(0, 0, 0, 0.85);
}
+ }
- .task-controls {
- display: flex;
- align-items: center;
- gap: 8px;
+ .task-section {
+ margin-bottom: 8px;
+ }
- .task-toggle {
- align-items: center;
-
- .anticon {
- font-size: 14px;
- color: #1677ff;
- vertical-align: middle;
- }
- }
-
- .ant-switch {
- &.ant-switch-small {
- min-width: 28px;
- height: 16px;
- line-height: 16px;
-
- .ant-switch-handle {
- width: 12px;
- height: 12px;
- }
-
- &.ant-switch-checked {
- background-color: #1677ff;
-
- .ant-switch-handle {
- left: calc(100% - 14px);
- }
- }
- }
- }
-
- .ant-btn-link {
- padding: 0;
- color: #1677ff;
-
- &:hover {
- color: #69b1ff;
- }
-
- &:disabled {
- color: rgba(0, 0, 0, 0.25);
- cursor: not-allowed;
- }
- }
- }
+ .section-title {
+ padding: 8px 16px;
+ background: #f5f5f5;
+ margin: 0;
+ font-size: 14px;
+ color: rgba(0, 0, 0, 0.85);
+ font-weight: 500;
+ border-bottom: 1px solid #e8e8e8;
}
.task-item {
@@ -91,21 +54,12 @@
width: 100%;
box-sizing: border-box;
cursor: pointer;
+ background: #fff;
&:hover {
background: #fafafa;
}
- &.task-completed {
- background: #fff;
- color: rgba(0, 0, 0, 0.65);
- }
-
- &.task-incomplete {
- background: #f5f5f5;
- color: rgba(0, 0, 0, 0.85);
- }
-
.task-content {
width: 100%;
}
@@ -137,7 +91,8 @@
.task-body {
margin-top: 4px;
- color: inherit;
+ color: rgba(0, 0, 0, 0.85);
+ font-weight: 500;
}
}
diff --git a/client/src/graphql/tasks.queries.js b/client/src/graphql/tasks.queries.js
index 554c21a18..bd4f8e3e8 100644
--- a/client/src/graphql/tasks.queries.js
+++ b/client/src/graphql/tasks.queries.js
@@ -287,6 +287,27 @@ export const QUERY_JOB_TASKS_PAGINATED = gql`
}
`;
+export const QUERY_MY_COMPLETE_TASKS_PAGINATED = gql`
+ ${PARTIAL_TASK_FIELDS}
+ query QUERY_MY_TASKS_PAGINATED(
+ $offset: Int
+ $limit: Int
+ $assigned_to: uuid!
+ $bodyshop: uuid!
+ $where: tasks_bool_exp
+ $order: [tasks_order_by!]!
+ ) {
+ tasks(offset: $offset, limit: $limit, order_by: $order, where: $where) {
+ ...TaskFields
+ }
+ tasks_aggregate(where: $where) {
+ aggregate {
+ count
+ }
+ }
+ }
+`;
+
export const QUERY_MY_TASKS_PAGINATED = gql`
${PARTIAL_TASK_FIELDS}
query QUERY_MY_TASKS_PAGINATED(