diff --git a/client/src/components/task-center/task-center.component.jsx b/client/src/components/task-center/task-center.component.jsx
index e1e39771b..b2466adda 100644
--- a/client/src/components/task-center/task-center.component.jsx
+++ b/client/src/components/task-center/task-center.component.jsx
@@ -1,5 +1,5 @@
import { Virtuoso } from "react-virtuoso";
-import { Badge, Button, Spin, Tooltip, Typography } from "antd";
+import { Badge, Button, Spin } from "antd";
import { useTranslation } from "react-i18next";
import { forwardRef, useMemo, useRef } from "react";
import day from "../../utils/day.js";
@@ -12,8 +12,6 @@ import {
QuestionCircleOutlined
} from "@ant-design/icons";
-const { Title } = Typography;
-
const TaskCenterComponent = forwardRef(
({ visible, tasks, loading, onTaskClick, onLoadMore, totalTasks, createNewTask }, ref) => {
const { t } = useTranslation();
@@ -25,13 +23,16 @@ const TaskCenterComponent = forwardRef(
[t("tasks.labels.upcoming")]: ,
[t("tasks.labels.no_due_date")]:
};
+
const groupedItems = useMemo(() => {
- const now = day();
+ const now = day("2025-07-09"); // Set to current date
const today = now.startOf("day");
const overdue = tasks.filter((t) => t.due_date && day(t.due_date).isBefore(today));
const dueToday = tasks.filter((t) => t.due_date && day(t.due_date).isSame(today, "day"));
- const upcoming = tasks.filter((t) => t.due_date && day(t.due_date).isAfter(today));
+ const upcoming = tasks.filter(
+ (t) => t.due_date && day(t.due_date).isAfter(today) && !day(t.due_date).isSame(today, "day")
+ );
const noDueDate = tasks.filter((t) => !t.due_date);
const makeGroup = (label, data) => (data.length ? [{ type: "section", label, tasks: data }] : []);
@@ -61,38 +62,30 @@ const TaskCenterComponent = forwardRef(
{sectionIcons[section.label]}
- {section.label}
+ {section.label} ({section.tasks.length})
{section.tasks.map((task) => {
const priorityColor = getPriorityColor(task.priority);
- const rowContent = (
+ return (
onTaskClick(task.id)}>
-
-
+ |
+
{task.title}
{t("notifications.labels.ro-number", {
ro_number: task.job?.ro_number || t("general.labels.na")
})}
- |
-
- {task.due_date && {day(task.due_date).fromNow()}}
- {!!priorityColor && }
- |
-
+
+
+
+ {task.due_date && {day(task.due_date).fromNow()}}
+ {!!priorityColor && }
+ |
);
-
- return task.description ? (
-
- {rowContent}
-
- ) : (
- rowContent
- );
})}
@@ -102,17 +95,18 @@ const TaskCenterComponent = forwardRef(
return (
-
{t("tasks.labels.my_tasks_center")}
+
+ {t("tasks.labels.my_tasks_center")} ({tasks.length})
+
} onClick={createNewTask} />
-
{loading && }
renderSection(section, index)}
/>
diff --git a/client/src/components/task-center/task-center.container.jsx b/client/src/components/task-center/task-center.container.jsx
index 4237aab34..66681fdce 100644
--- a/client/src/components/task-center/task-center.container.jsx
+++ b/client/src/components/task-center/task-center.container.jsx
@@ -7,9 +7,10 @@ import { useSocket } from "../../contexts/SocketIO/useSocket";
import { useIsEmployee } from "../../utils/useIsEmployee";
import TaskCenterComponent from "./task-center.component";
import { setModalContext } from "../../redux/modals/modals.actions";
-import { QUERY_MY_ACTIVE_TASKS_PAGINATED } from "../../graphql/tasks.queries";
+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 mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -30,35 +31,55 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
return employee?.id || null;
}, [bodyshop, currentUser]);
- const { data, loading, fetchMore } = useQuery(QUERY_MY_ACTIVE_TASKS_PAGINATED, {
+ // Query 1: Tasks with due dates
+ const { data: dueDateData, loading: dueLoading } = useQuery(QUERY_TASKS_WITH_DUE_DATES, {
variables: {
bodyshop: bodyshop?.id,
assigned_to: assignedToId,
- offset: 0,
- limit: 50,
- order: [{ due_date: "asc_nulls_last" }, { created_at: "desc" }]
+ order: [{ due_date: "asc" }, { created_at: "desc" }]
},
skip: !bodyshop?.id || !assignedToId || !isEmployee || !currentUser?.email,
fetchPolicy: "cache-and-network",
pollInterval: isConnected ? 0 : POLL_INTERVAL
});
- useEffect(() => {
- if (data?.tasks) {
- setTasks(data.tasks);
- }
- }, [data]);
+ // Query 2: Tasks with no due date (paginated)
+ const {
+ data: noDueDateData,
+ loading: noDueLoading,
+ fetchMore
+ } = useQuery(QUERY_TASKS_NO_DUE_DATE_PAGINATED, {
+ variables: {
+ bodyshop: bodyshop?.id,
+ assigned_to: assignedToId,
+ order: [{ created_at: "desc" }],
+ limit: LIMIT,
+ offset: 0
+ },
+ skip: !bodyshop?.id || !assignedToId || !isEmployee || !currentUser?.email,
+ fetchPolicy: "cache-and-network",
+ pollInterval: isConnected ? 0 : POLL_INTERVAL
+ });
+ // Combine tasks from both queries
+ useEffect(() => {
+ const dueDateTasks = dueDateData?.tasks || [];
+ const noDueDateTasks = noDueDateData?.tasks || [];
+ setTasks([...dueDateTasks, ...noDueDateTasks]);
+ }, [dueDateData, noDueDateData]);
+
+ // Handle pagination for no-due-date tasks
const handleLoadMore = () => {
fetchMore({
variables: {
- offset: tasks.length
+ offset: noDueDateData?.tasks?.length || 0
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return {
...prev,
- tasks: [...prev.tasks, ...fetchMoreResult.tasks]
+ tasks: [...prev.tasks, ...fetchMoreResult.tasks],
+ tasks_aggregate: fetchMoreResult.tasks_aggregate
};
}
});
@@ -87,10 +108,10 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU
visible={visible}
onClose={onClose}
tasks={tasks}
- loading={loading}
+ loading={dueLoading || noDueLoading}
onTaskClick={handleTaskClick}
onLoadMore={handleLoadMore}
- totalTasks={data?.tasks_aggregate?.aggregate?.count || 0}
+ totalTasks={noDueDateData?.tasks_aggregate?.aggregate?.count || 0}
createNewTask={createNewTask}
/>
);
diff --git a/client/src/components/task-center/task-center.styles.scss b/client/src/components/task-center/task-center.styles.scss
index b19f7148e..b033ebdef 100644
--- a/client/src/components/task-center/task-center.styles.scss
+++ b/client/src/components/task-center/task-center.styles.scss
@@ -50,8 +50,8 @@
}
.section-title {
- padding: 3px 10px;
- margin: 0;
+ padding: 0px 10px;
+ margin: 0px;
//font-size: 12px;
background: #f5f5f5;
font-weight: 650;
diff --git a/client/src/graphql/tasks.queries.js b/client/src/graphql/tasks.queries.js
index 5745e8045..c9496fcea 100644
--- a/client/src/graphql/tasks.queries.js
+++ b/client/src/graphql/tasks.queries.js
@@ -67,6 +67,105 @@ export const PARTIAL_TASK_FIELDS = gql`
}
`;
+export const PARTIAL_TASK_CENTER_FIELDS = gql`
+ fragment TaskFields on tasks {
+ id
+ title
+ description
+ due_date
+ priority
+ jobid
+ job {
+ ro_number
+ }
+ joblineid
+ partsorderid
+ billid
+ remind_at
+ created_at
+ assigned_to
+ bodyshopid
+ deleted
+ completed
+ }
+`;
+
+export const QUERY_TASKS_WITH_DUE_DATES = gql`
+ ${PARTIAL_TASK_CENTER_FIELDS}
+ query QUERY_TASKS_WITH_DUE_DATES($bodyshop: uuid!, $assigned_to: uuid!, $order: [tasks_order_by!]!) {
+ tasks(
+ where: {
+ bodyshopid: { _eq: $bodyshop }
+ assigned_to: { _eq: $assigned_to }
+ deleted: { _eq: false }
+ completed: { _eq: false }
+ due_date: { _is_null: false }
+ }
+ order_by: $order
+ ) {
+ ...TaskFields
+ }
+ }
+`;
+export const QUERY_TASKS_NO_DUE_DATE_PAGINATED = gql`
+ ${PARTIAL_TASK_CENTER_FIELDS}
+ query QUERY_TASKS_NO_DUE_DATE_PAGINATED(
+ $bodyshop: uuid!
+ $assigned_to: uuid!
+ $order: [tasks_order_by!]!
+ $limit: Int!
+ $offset: Int!
+ ) {
+ tasks(
+ where: {
+ bodyshopid: { _eq: $bodyshop }
+ assigned_to: { _eq: $assigned_to }
+ deleted: { _eq: false }
+ completed: { _eq: false }
+ due_date: { _is_null: true }
+ }
+ order_by: $order
+ limit: $limit
+ offset: $offset
+ ) {
+ ...TaskFields
+ }
+ tasks_aggregate(
+ where: {
+ bodyshopid: { _eq: $bodyshop }
+ assigned_to: { _eq: $assigned_to }
+ deleted: { _eq: false }
+ completed: { _eq: false }
+ due_date: { _is_null: true }
+ }
+ ) {
+ aggregate {
+ count
+ }
+ }
+ }
+`;
+/**
+ * Query to get the count of my tasks
+ * @type {DocumentNode}
+ */
+export const QUERY_MY_TASKS_COUNT = gql`
+ query QUERY_MY_TASKS_COUNT($assigned_to: uuid!, $bodyshopid: uuid!) {
+ tasks_aggregate(
+ where: {
+ assigned_to: { _eq: $assigned_to }
+ bodyshopid: { _eq: $bodyshopid }
+ completed: { _eq: false }
+ deleted: { _eq: false }
+ }
+ ) {
+ aggregate {
+ count
+ }
+ }
+ }
+`;
+
export const QUERY_GET_TASK_BY_ID = gql`
${PARTIAL_TASK_FIELDS}
query QUERY_GET_TASK_BY_ID($id: uuid!) {
@@ -287,27 +386,6 @@ 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_ACTIVE_TASKS_PAGINATED = gql`
${PARTIAL_TASK_FIELDS}
query QUERY_MY_ACTIVE_TASKS_PAGINATED(
@@ -439,24 +517,3 @@ export const MUTATION_UPDATE_TASK = gql`
}
}
`;
-
-/**
- * Query to get the count of my tasks
- * @type {DocumentNode}
- */
-export const QUERY_MY_TASKS_COUNT = gql`
- query QUERY_MY_TASKS_COUNT($assigned_to: uuid!, $bodyshopid: uuid!) {
- tasks_aggregate(
- where: {
- assigned_to: { _eq: $assigned_to }
- bodyshopid: { _eq: $bodyshopid }
- completed: { _eq: false }
- deleted: { _eq: false }
- }
- ) {
- aggregate {
- count
- }
- }
- }
-`;