feature/IO-3291-Tasks-Notifications: Checkpoint
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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" />}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// SocketProvider.js
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import SocketIO from "socket.io-client";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
@@ -16,7 +15,14 @@ import {
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { SocketContext, INITIAL_NOTIFICATIONS } from "./useSocket.js";
|
||||
import { INITIAL_NOTIFICATIONS, SocketContext } from "./useSocket.js";
|
||||
import {
|
||||
QUERY_MY_TASKS_COUNT,
|
||||
QUERY_TASKS_NO_DUE_DATE_PAGINATED,
|
||||
QUERY_TASKS_WITH_DUE_DATES
|
||||
} from "../../graphql/tasks.queries";
|
||||
|
||||
const LIMIT = 50; // Tasks per page for no-due-date tasks
|
||||
|
||||
/**
|
||||
* Socket Provider - Scenario Notifications / Web Socket related items
|
||||
@@ -168,6 +174,103 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => {
|
||||
case "alert-update":
|
||||
store.dispatch(addAlerts(message.payload));
|
||||
break;
|
||||
case "task-created":
|
||||
case "task-updated":
|
||||
case "task-deleted":
|
||||
const payload = message.payload;
|
||||
const assignedToId = bodyshop?.employees?.find((e) => e.user_email === currentUser?.email)?.id;
|
||||
if (!assignedToId || payload.assigned_to !== assignedToId) return;
|
||||
|
||||
// Handle due date tasks cache update
|
||||
const dueVars = {
|
||||
bodyshop: bodyshop?.id,
|
||||
assigned_to: assignedToId,
|
||||
order: [{ due_date: "asc" }, { created_at: "desc" }]
|
||||
};
|
||||
let hasDueCache = false;
|
||||
try {
|
||||
client.readQuery({ query: QUERY_TASKS_WITH_DUE_DATES, variables: dueVars });
|
||||
hasDueCache = true;
|
||||
} catch (e) {}
|
||||
if (hasDueCache) {
|
||||
client
|
||||
.query({ query: QUERY_TASKS_WITH_DUE_DATES, variables: dueVars, fetchPolicy: "network-only" })
|
||||
.then(({ data }) => {
|
||||
client.writeQuery({ query: QUERY_TASKS_WITH_DUE_DATES, variables: dueVars, data });
|
||||
})
|
||||
.catch((e) => console.error("Task due refetch error:", e));
|
||||
}
|
||||
|
||||
// Handle no due date tasks cache update
|
||||
const originalNoDueVars = {
|
||||
bodyshop: bodyshop?.id,
|
||||
assigned_to: assignedToId,
|
||||
order: [{ created_at: "desc" }],
|
||||
limit: LIMIT,
|
||||
offset: 0
|
||||
};
|
||||
let currentLength = 0;
|
||||
try {
|
||||
const existing = client.readQuery({
|
||||
query: QUERY_TASKS_NO_DUE_DATE_PAGINATED,
|
||||
variables: originalNoDueVars
|
||||
});
|
||||
currentLength = existing?.tasks?.length || 0;
|
||||
} catch (e) {}
|
||||
if (currentLength > 0) {
|
||||
let fetchLimit = currentLength;
|
||||
if (message.type === "task-created") {
|
||||
fetchLimit += 1;
|
||||
} else if (message.type === "task-deleted") {
|
||||
fetchLimit = Math.max(currentLength - 1, 0);
|
||||
}
|
||||
if (fetchLimit > 0) {
|
||||
const fetchVars = { ...originalNoDueVars, limit: fetchLimit };
|
||||
client
|
||||
.query({
|
||||
query: QUERY_TASKS_NO_DUE_DATE_PAGINATED,
|
||||
variables: fetchVars,
|
||||
fetchPolicy: "network-only"
|
||||
})
|
||||
.then(({ data }) => {
|
||||
client.writeQuery({
|
||||
query: QUERY_TASKS_NO_DUE_DATE_PAGINATED,
|
||||
variables: originalNoDueVars,
|
||||
data: {
|
||||
tasks: data.tasks,
|
||||
tasks_aggregate: data.tasks_aggregate
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((e) => console.error("Task no due refetch error:", e));
|
||||
} else {
|
||||
client.writeQuery({
|
||||
query: QUERY_TASKS_NO_DUE_DATE_PAGINATED,
|
||||
variables: originalNoDueVars,
|
||||
data: { tasks: [], tasks_aggregate: { aggregate: { count: 0 } } }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Handle task count cache update
|
||||
const countVars = {
|
||||
assigned_to: assignedToId,
|
||||
bodyshopid: bodyshop?.id
|
||||
};
|
||||
let hasCountCache = false;
|
||||
try {
|
||||
client.readQuery({ query: QUERY_MY_TASKS_COUNT, variables: countVars });
|
||||
hasCountCache = true;
|
||||
} catch (e) {}
|
||||
if (hasCountCache) {
|
||||
client
|
||||
.query({ query: QUERY_MY_TASKS_COUNT, variables: countVars, fetchPolicy: "network-only" })
|
||||
.then(({ data }) => {
|
||||
client.writeQuery({ query: QUERY_MY_TASKS_COUNT, variables: countVars, data });
|
||||
})
|
||||
.catch((e) => console.error("Task count refetch error:", e));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user