feature/IO-3291-Tasks-Notifications: Checkpoint
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
|||||||
QUERY_TASKS_WITH_DUE_DATES
|
QUERY_TASKS_WITH_DUE_DATES
|
||||||
} from "../../graphql/tasks.queries";
|
} from "../../graphql/tasks.queries";
|
||||||
|
|
||||||
const LIMIT = 50; // Tasks per page for no-due-date tasks
|
const LIMIT = INITIAL_NOTIFICATIONS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Socket Provider - Scenario Notifications / Web Socket related items
|
* Socket Provider - Scenario Notifications / Web Socket related items
|
||||||
@@ -181,95 +181,136 @@ const SocketProvider = ({ children, bodyshop, navigate, currentUser }) => {
|
|||||||
const assignedToId = bodyshop?.employees?.find((e) => e.user_email === currentUser?.email)?.id;
|
const assignedToId = bodyshop?.employees?.find((e) => e.user_email === currentUser?.email)?.id;
|
||||||
if (!assignedToId || payload.assigned_to !== assignedToId) return;
|
if (!assignedToId || payload.assigned_to !== assignedToId) return;
|
||||||
|
|
||||||
// Handle due date tasks cache update
|
|
||||||
const dueVars = {
|
const dueVars = {
|
||||||
bodyshop: bodyshop?.id,
|
bodyshop: bodyshop?.id,
|
||||||
assigned_to: assignedToId,
|
assigned_to: assignedToId,
|
||||||
order: [{ due_date: "asc" }, { created_at: "desc" }]
|
order: [{ due_date: "asc" }, { created_at: "desc" }]
|
||||||
};
|
};
|
||||||
let hasDueCache = false;
|
const noDueVars = {
|
||||||
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,
|
bodyshop: bodyshop?.id,
|
||||||
assigned_to: assignedToId,
|
assigned_to: assignedToId,
|
||||||
order: [{ created_at: "desc" }],
|
order: [{ created_at: "desc" }],
|
||||||
limit: LIMIT,
|
limit: LIMIT,
|
||||||
offset: 0
|
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 = {
|
const countVars = {
|
||||||
assigned_to: assignedToId,
|
assigned_to: assignedToId,
|
||||||
bodyshopid: bodyshop?.id
|
bodyshopid: bodyshop?.id
|
||||||
};
|
};
|
||||||
let hasCountCache = false;
|
|
||||||
try {
|
// Helper to update a list in cache locally
|
||||||
client.readQuery({ query: QUERY_MY_TASKS_COUNT, variables: countVars });
|
const updateListCache = (query, vars, action) => {
|
||||||
hasCountCache = true;
|
// action: 'add' or 'remove'
|
||||||
} catch (e) {}
|
try {
|
||||||
if (hasCountCache) {
|
const current = client.readQuery({ query, variables: vars });
|
||||||
client
|
if (!current) return; // List not loaded yet, skip
|
||||||
.query({ query: QUERY_MY_TASKS_COUNT, variables: countVars, fetchPolicy: "network-only" })
|
|
||||||
.then(({ data }) => {
|
let updatedTasks = [...current.tasks];
|
||||||
client.writeQuery({ query: QUERY_MY_TASKS_COUNT, variables: countVars, data });
|
let delta = 0;
|
||||||
})
|
|
||||||
.catch((e) => console.error("Task count refetch error:", e));
|
if (action === "remove") {
|
||||||
|
const prevLength = updatedTasks.length;
|
||||||
|
updatedTasks = updatedTasks.filter((task) => task.id !== payload.id);
|
||||||
|
if (updatedTasks.length < prevLength) delta -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "add") {
|
||||||
|
const exists = updatedTasks.some((task) => task.id === payload.id);
|
||||||
|
if (!exists) {
|
||||||
|
const newTask = { ...payload, __typename: "tasks" };
|
||||||
|
updatedTasks.push(newTask);
|
||||||
|
delta += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the array based on the query type if delta !== 0
|
||||||
|
if (delta !== 0) {
|
||||||
|
if (query === QUERY_TASKS_WITH_DUE_DATES) {
|
||||||
|
updatedTasks.sort((a, b) => {
|
||||||
|
const da = new Date(a.due_date);
|
||||||
|
const db = new Date(b.due_date);
|
||||||
|
if (da < db) return -1;
|
||||||
|
if (da > db) return 1;
|
||||||
|
const ca = new Date(a.created_at);
|
||||||
|
const cb = new Date(b.created_at);
|
||||||
|
return cb - ca; // desc
|
||||||
|
});
|
||||||
|
} else if (query === QUERY_TASKS_NO_DUE_DATE_PAGINATED) {
|
||||||
|
updatedTasks.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = { ...current, tasks: updatedTasks };
|
||||||
|
|
||||||
|
// Adjust aggregate count for no due date query
|
||||||
|
if (query === QUERY_TASKS_NO_DUE_DATE_PAGINATED && delta !== 0 && current.tasks_aggregate) {
|
||||||
|
const newCount = Math.max(0, current.tasks_aggregate.aggregate.count + delta);
|
||||||
|
data = {
|
||||||
|
...data,
|
||||||
|
tasks_aggregate: {
|
||||||
|
...current.tasks_aggregate,
|
||||||
|
aggregate: {
|
||||||
|
...current.tasks_aggregate.aggregate,
|
||||||
|
count: newCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
client.writeQuery({ query, variables: vars, data });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating task list cache:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update lists based on event type
|
||||||
|
if (message.type === "task-deleted") {
|
||||||
|
updateListCache(QUERY_TASKS_WITH_DUE_DATES, dueVars, "remove");
|
||||||
|
updateListCache(QUERY_TASKS_NO_DUE_DATE_PAGINATED, noDueVars, "remove");
|
||||||
|
} else {
|
||||||
|
const targetQuery = payload.due_date ? QUERY_TASKS_WITH_DUE_DATES : QUERY_TASKS_NO_DUE_DATE_PAGINATED;
|
||||||
|
const targetVars = payload.due_date ? dueVars : noDueVars;
|
||||||
|
|
||||||
|
if (message.type === "task-updated") {
|
||||||
|
// Remove from both in case of due_date change
|
||||||
|
updateListCache(QUERY_TASKS_WITH_DUE_DATES, dueVars, "remove");
|
||||||
|
updateListCache(QUERY_TASKS_NO_DUE_DATE_PAGINATED, noDueVars, "remove");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to the target list
|
||||||
|
updateListCache(targetQuery, targetVars, "add");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locally update the total count (no network call)
|
||||||
|
try {
|
||||||
|
const currentCountQuery = client.readQuery({ query: QUERY_MY_TASKS_COUNT, variables: countVars });
|
||||||
|
if (currentCountQuery) {
|
||||||
|
let countDelta = 0;
|
||||||
|
if (message.type === "task-created") countDelta = 1;
|
||||||
|
else if (message.type === "task-deleted") countDelta = -1;
|
||||||
|
// For "task-updated", assume no change to count unless specific logic (e.g., completion)
|
||||||
|
|
||||||
|
if (countDelta !== 0) {
|
||||||
|
const newCount = Math.max(0, currentCountQuery.tasks_aggregate.aggregate.count + countDelta);
|
||||||
|
client.writeQuery({
|
||||||
|
query: QUERY_MY_TASKS_COUNT,
|
||||||
|
variables: countVars,
|
||||||
|
data: {
|
||||||
|
tasks_aggregate: {
|
||||||
|
__typename: "tasks_aggregate",
|
||||||
|
aggregate: {
|
||||||
|
__typename: "tasks_aggregate_fields",
|
||||||
|
count: newCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating task count cache:", error);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -146,17 +146,10 @@ const handlePaymentsChange = async (req, res) =>
|
|||||||
processNotificationEvent(req, res, "req.body.event.new.jobid", "Payments Changed Notification Event Handled.");
|
processNotificationEvent(req, res, "req.body.event.new.jobid", "Payments Changed Notification Event Handled.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle tasks change notifications.
|
* Handle task socket emit.
|
||||||
*
|
* @param req
|
||||||
* @param {Object} req - Express request object.
|
|
||||||
* @param {Object} res - Express response object.
|
|
||||||
* @returns {Promise<Object>} JSON response with a success message.
|
|
||||||
*/
|
*/
|
||||||
const handleTasksChange = async (req, res) => {
|
const handleTaskSocketEmit = (req) => {
|
||||||
console.log("Handling tasks change notification...!!!!!!!!!!!!");
|
|
||||||
// Handle Notification Event
|
|
||||||
processNotificationEvent(req, res, "req.body.event.new.jobid", "Tasks Notifications Event Handled.");
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
logger,
|
logger,
|
||||||
ioRedis,
|
ioRedis,
|
||||||
@@ -184,7 +177,7 @@ const handleTasksChange = async (req, res) => {
|
|||||||
|
|
||||||
if (newData.deleted && !oldData.deleted) {
|
if (newData.deleted && !oldData.deleted) {
|
||||||
type = "task-deleted";
|
type = "task-deleted";
|
||||||
taskData = { id: newData.id };
|
taskData = { id: newData.id, assigned_to: newData.assigned_to };
|
||||||
} else if (!newData.deleted && oldData.deleted) {
|
} else if (!newData.deleted && oldData.deleted) {
|
||||||
type = "task-created";
|
type = "task-created";
|
||||||
} else if (!newData.deleted) {
|
} else if (!newData.deleted) {
|
||||||
@@ -202,6 +195,21 @@ const handleTasksChange = async (req, res) => {
|
|||||||
logger.log("tasks-event-missing-data", "error", "notifications", null, { bodyshopId, hasIo: !!ioRedis, type });
|
logger.log("tasks-event-missing-data", "error", "notifications", null, { bodyshopId, hasIo: !!ioRedis, type });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle tasks change notifications.
|
||||||
|
* Note: this also handles task center notifications.
|
||||||
|
*
|
||||||
|
* @param {Object} req - Express request object.
|
||||||
|
* @param {Object} res - Express response object.
|
||||||
|
* @returns {Promise<Object>} JSON response with a success message.
|
||||||
|
*/
|
||||||
|
const handleTasksChange = async (req, res) => {
|
||||||
|
// Handle Notification Event
|
||||||
|
processNotificationEvent(req, res, "req.body.event.new.jobid", "Tasks Notifications Event Handled.");
|
||||||
|
handleTaskSocketEmit(req);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle time tickets change notifications.
|
* Handle time tickets change notifications.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user