Duffer Derek
import * as dateFns from "date-fns";
import { format } from "date-fns";
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { showToast } from "../components/atom/toaster/toaster";
import { updateOrAddTasks } from "../utils/commonFunctions";
import { useAuthContext } from "./useAuthContext";
import { useDataContext } from "./useDataContext";
const unAssignedPartner = {
id: null,
name: "Make Unassigned",
type: null,
email: null,
phone: null,
firstname: null,
lastname: null,
};
/**
* Format subtask data, modifying it to include shared data if applicable.
* @param {Array} subTasks
* @returns {Array}
*/
const formatSubTaskData = (subTasks) => {
let formattedData = subTasks;
let sharedData = [];
subTasks.forEach((subTask) => {
// Check if the subtask has shared_time (indicating it's shared) or if it's marked for deletion
if (
(subTask?.shared_time && subTask?.shared_time !== "0") ||
(subTask?.shared_time == null && subTask.delete == true)
) {
sharedData = {
date: subTask?.date,
notes: subTask?.notes,
time: subTask?.shared_time,
user_id: subTask?.user?.id,
shared: 1,
};
// If the subtask is marked for deletion, set the delete flag in sharedData
if (subTask.delete == true) {
sharedData.delete = true;
}
formattedData.push(sharedData);
}
});
return formattedData;
};
const useMainTaskView = () => {
const [subTasks, setSubTasks] = useState([]);
const { taskDetails, filterOptions, filters, dispatch } = useDataContext();
const [taskPartner, setTaskPartner] = useState();
const [startDate, setStartDate] = useState();
const [endDate, setEndDate] = useState();
const { access_token } = useAuthContext();
const [errorDate, setErrorDate] = useState({
date: "",
message: "",
key: "",
});
const taskPartnerOptions = [
...(filterOptions?.partners || []),
unAssignedPartner,
];
/**
* Handle changes to a subtask field.
* Updates the specified subtask with the new value for the specified key.
* @param {any} value
* @param {string} key
* @param {string} date
*/
const handleSubTaskFieldChange = (value, key, date) => {
// Find the index of the subtask with the specified date
const index = subTasks.findIndex((sub) => sub.date === date);
// Find the subtask object with the specified date
const subTask = subTasks.find((sub) => sub.date === date);
// Create a new subtask object with the updated field value
const updatedSubTask = { ...subTask, [key]: value };
// If the subtask is marked for deletion, reset shared_time and user fields
if (updatedSubTask.delete == true) {
updatedSubTask.shared_time = null;
updatedSubTask.user = null;
}
// If notes field is undefined, set it to an empty string for adding subtask without notes
if (updatedSubTask.notes === undefined) {
updatedSubTask.notes = "";
}
let updatedSubTasks = [...subTasks];
updatedSubTasks[index] = updatedSubTask;
setSubTasks(updatedSubTasks);
};
/**
* Set data for a single task, including user details if provided.
* @param {Object} Task
* @param {Object} user
*/
const setSingleTaskData = (task, user = {}) => {
const userDetails = {
id: user.userId,
name: user.username,
phone: user.phone,
email: user.email,
type: user.type,
firstname: user.firstname,
lastname: user.lastname,
};
const updatedTask = {
...task,
user: userDetails,
};
// setting updatedTask into datacontext
dispatch({
type: "SINGLE_TASK",
payload: updatedTask,
});
};
useEffect(() => {
if (taskDetails?.user) {
setTaskPartner(taskDetails?.user);
setStartDate(new Date(taskDetails?.startDate));
setEndDate(new Date(taskDetails?.endDate));
}
if (taskDetails) {
generateSubTasks(taskDetails);
}
}, [taskDetails]);
/**
* Generate subtasks for all dates between start and end date of a task.
* If subtasks are already provided and the task is shared, use the provided subtasks.
* If subtasks are not provided or the task is not shared, generate subtasks for each date.
* @param {*} taskDetails
*/
const generateSubTasks = (taskDetails) => {
// Extracting necessary details from the taskDetails
const startDate = taskDetails.startDate;
const endDate = taskDetails.endDate;
const subTasks = taskDetails.subtasks || [];
let list = [];
// Checking if the task is shared and if subtasks are already provided
if (taskDetails?.shared && subTasks.length > 0) {
// If shared and subtasks are provided, directly add them to the list
list.push(...subTasks);
} else {
let start = new Date(startDate);
do {
const dayOfWeek = start.getDay();
const date = start.toDateString();
const user_id = taskDetails?.user?.id ? taskDetails?.user?.id : null;
// Filtering subtasks that match the current date
const matchingSubTasks = subTasks.filter(
(subTask) => subTask.date === date
);
// If matching subtasks are found, add them to the list
if (matchingSubTasks.length > 0) {
list.push(...matchingSubTasks);
} else {
list.push({
date,
user_id,
});
}
start = dateFns.addDays(start, 1);
} while (
// Continue loop until start date is before the end date or start date is the same as the end date
dateFns.isBefore(start, new Date(endDate)) ||
dateFns.isSameDay(start, new Date(endDate))
);
}
setSubTasks(list);
};
/**
* Handle change in task partner dropdown selection.
* Updates the taskDetails based on the selected value.
* @param {Object} value
*/
const handleTaskPartnerDropdownChange = (value) => {
const updatedTask = {
...taskDetails,
};
//if user select unassigned then color should be "#d3d3d3"
if (value.id == null) {
updatedTask.unassigned = true;
updatedTask.user = unAssignedPartner;
updatedTask.country_side_color = "#d3d3d3";
} else {
// Find the color corresponding to the selected countryside
const color = filterOptions.lansdel.find(
(category) => category.name === updatedTask.countryside
)?.color;
updatedTask.unassigned = false;
updatedTask.user = value;
updatedTask.country_side_color = color;
}
// set updatedTask into datacontext
dispatch({
type: "SINGLE_TASK",
payload: updatedTask,
});
};
/**
* Save the data of the task and its subtasks.
* Shows confirmation messages if necessary.
* @param {function} setShowContent
* @param {function} closePopupBodyClick
*/
const saveData = async (setShowContent, closePopupBodyClick) => {
if (taskDetails.unassigned == true) {
// Show a confirmation message if the task is unassigned
const message =
"Now the task is unassigned, so if any subtask is created for this task, all will be deleted. Click 'OK' to confirm";
toastMessage(message, setShowContent, closePopupBodyClick);
} else {
// Check for validation errors before saving
const hasError = checkValidation();
if (hasError) return;
const showToastMessage = subTasks?.some((subTask) => {
if (!subTask.id || !subTask.date) return false;
const subTaskDate = new Date(subTask.date);
return subTaskDate < startDate || subTaskDate > endDate;
}) || false;
// show toast message before save data
if (showToastMessage) {
const message =
"The changed date is not matching with its subtask do you want to delete that subtask and update the task";
toastMessage(message, setShowContent, closePopupBodyClick);
} else {
// If no toast message needs to be shown, update task and subtasks
upadteTaskAndSubTask(setShowContent, closePopupBodyClick);
}
}
dispatch({
type: "POP_UP_STATUS",
payload: false,
});
};
/**
* Check validation for subtasks.
* @returns {boolean}
*/
const checkValidation = () => {
let hasError = false;
subTasks.forEach((subTask) => {
const isNotesEmpty = subTask.notes === undefined;
const isTimeEmpty =
subTask.time === undefined ||
subTask.time == "" ||
subTask.time == "00:00";
const isPartnerEmpty =
subTask.user == undefined ||
subTask.user.name == null ||
subTask.user == null;
const isSharedTimeEmpty =
subTask.shared_time == undefined ||
subTask.shared_time == null ||
subTask.shared_time == "00:00";
// If notes and time are not both empty or both filled, set error and flag hasError
if ((!isNotesEmpty && isTimeEmpty) || (!isTimeEmpty && isNotesEmpty)) {
setErrorDate({
date: subTask.date,
message: "Time not be empty",
key: "notes",
});
hasError = true;
return hasError;
} else {
// If both partner and shared time should have values but one of them is missing, set error
if (
(!isPartnerEmpty && isSharedTimeEmpty) ||
(isPartnerEmpty && !isSharedTimeEmpty)
) {
setErrorDate({
date: subTask.date,
message: "Both shared partner and shared time should have values",
key: "shared",
});
hasError = true;
return hasError;
}
// If both notes and time are empty but partner and shared time are filled, set error and flag hasError
if (
isNotesEmpty &&
isTimeEmpty &&
!isPartnerEmpty &&
!isSharedTimeEmpty
) {
setErrorDate({
date: subTask.date,
message: "please fill Subtask time before sharing subtask ",
key: "notes",
});
hasError = true;
return hasError;
}
}
});
return hasError;
};
const toastMessage = (message, setShowContent, closePopupBodyClick) => {
const toastId = showToast(
"ok",
message,
{
autoClose: 3000,
position: "top-center",
},
0,
() => {
upadteTaskAndSubTask(setShowContent, closePopupBodyClick);
toast.dismiss(toastId);
},
() => toast.dismiss(toastId)
);
};
/**
* Update task and its subtasks.
* @param {function} setShowContent
* @param {function} closePopupBodyClick
*/
const upadteTaskAndSubTask = async (setShowContent, closePopupBodyClick) => {
// Hide content
setShowContent(false);
let finalSubTaskData = {
tasks: {
data: [],
item_id: taskDetails?.item_id,
},
};
let taskData = {
item_id: taskDetails?.item_id,
start_date: format(startDate, "yyyy-MM-dd"),
end_date: format(endDate, "yyyy-MM-dd"),
user_id: taskPartner?.id,
country_side_color: taskDetails?.country_side_color,
};
if (taskDetails.unassigned !== true) {
// Filter out subtasks without time, convert date to appropriate format and add user_id and shared fields
let formattedSubTasks = subTasks
.filter((subTask) => subTask?.time)
.map((subTask) => ({
...subTask,
date: new Date(format(subTask?.date, "yyyy-MM-dd")),
user_id: taskPartner?.id,
shared: 0,
}));
const includeSharedSubTask = formatSubTaskData(formattedSubTasks);
finalSubTaskData.tasks.data = [
...finalSubTaskData.tasks.data,
...includeSharedSubTask,
];
} else {
taskData.unassigned = true;
}
const finalData = {
sub_tasks: finalSubTaskData,
task_data: taskData,
filter: filters,
};
// Update or add tasks using finalData and access token
const response = await updateOrAddTasks(finalData, access_token);
// Set response data
setData(response);
// Close popup
closePopupBodyClick();
// Show content
setShowContent(true);
};
/**
* Set response data to data context
* @param {*} response
*/
const setData = (response) => {
dispatch({
type: "DATA",
payload: response?.data?.tasks?.assigned,
});
dispatch({
type: "UNASSIGNED_TASK",
payload: response?.data?.tasks?.unassigned,
});
};
const openMainTask = () => {
document.body.style.overflow = "hidden";
dispatch({
type: "POP_UP_STATUS",
payload: true,
});
};
const closeMainTask = () => {
setErrorDate({
date: "",
message: "",
key: "",
});
document.body.style.overflow = "visible";
dispatch({
type: "POP_UP_STATUS",
payload: false,
});
};
return {
setSingleTaskData,
taskDetails,
filterOptions,
startDate,
endDate,
taskPartner,
saveData,
subTasks,
setSubTasks,
setTaskPartner,
taskPartner,
startDate,
setStartDate,
endDate,
setEndDate,
handleSubTaskFieldChange,
errorDate,
taskPartnerOptions,
handleTaskPartnerDropdownChange,
openMainTask,
closeMainTask,
};
};
export default useMainTaskView;
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists