bule2024

Untitled

Nov 20th, 2025
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 392.93 KB | Source Code | 0 0
  1.    <script>
  2.  
  3.             let currentEODUserId = null;
  4.  
  5. function openEODSummary(userId) {
  6.   currentEODUserId = userId;
  7.   document.getElementById('eodSummaryModal').classList.remove('hidden');
  8.   fetchAndRenderEOD(userId, 'last_7_days'); // default filter
  9. }
  10.  
  11. function closeEODModal() {
  12.   document.getElementById('eodSummaryModal').classList.add('hidden');
  13. }
  14.  
  15. document.getElementById('closeEODModalBtn').addEventListener('click', closeEODModal);
  16.  
  17. document.getElementById('dateFilter').addEventListener('change', () => {
  18.   const filterValue = document.getElementById('dateFilter').value;
  19.   fetchAndRenderEOD(currentEODUserId, filterValue);
  20. });
  21.  
  22. async function fetchAndRenderEOD(userId, filterValue) {
  23.   const tbody = document.getElementById('eodTableBody');
  24.   tbody.innerHTML = '<tr><td colspan="4">Loading...</td></tr>';
  25.  
  26.   try {
  27.     const res = await fetch(`/tasks/api/eod-report/?user=${userId}&filter=${filterValue}`, {
  28.       credentials: 'include'
  29.     });
  30.  
  31.     if (!res.ok) {
  32.       throw new Error(`HTTP error! Status: ${res.status}`);
  33.     }
  34.  
  35.     const data = await res.json();
  36.     tbody.innerHTML = '';
  37.  
  38.     // Determine date list
  39.     let allDates = [];
  40.     if (filterValue === "last_7_days") {
  41.       allDates = getPastDates(7);
  42.     } else if (filterValue === "last_15_days") {
  43.       allDates = getPastDates(15);
  44.     } else {
  45.       allDates = getMonthDates(filterValue); // month name β†’ array of YYYY-MM-DD
  46.     }
  47.  
  48.     allDates.forEach(date => {
  49.       const entries = data.filter(item => item.date === date);
  50.  
  51.       if (entries.length > 0) {
  52.         entries.forEach((entry, index) => {
  53.           const row = document.createElement("tr");
  54.  
  55.           const dateCell = document.createElement("td");
  56.           dateCell.textContent = index === 0 ? date : "";
  57.  
  58.           const projectCell = document.createElement("td");
  59.           projectCell.textContent = entry.project_name;
  60.  
  61.           const summaryCell = document.createElement("td");
  62.           summaryCell.innerHTML = `${entry.task_name} -- ${entry.text}
  63.             <span class="status-chip ${entry.task_status === 'C' ? 'Complete' : 'Incomplete'}">
  64.               ${entry.task_status === 'C' ? 'Complete' : 'Incomplete'}
  65.             </span>`;
  66.  
  67.           const bountyCell = document.createElement("td");
  68.           bountyCell.textContent = entry.bounty;
  69.  
  70.           row.append(dateCell, projectCell, summaryCell, bountyCell);
  71.           tbody.appendChild(row);
  72.         });
  73.       } else {
  74.         const row = document.createElement("tr");
  75.         row.innerHTML = `
  76.           <td>${date}</td>
  77.           <td>-</td>
  78.           <td>No EOD submitted today</td>
  79.           <td>-</td>
  80.         `;
  81.         tbody.appendChild(row);
  82.       }
  83.     });
  84.  
  85.   } catch (err) {
  86.     console.error(err);
  87.     tbody.innerHTML = '<tr><td colspan="4">Error loading data</td></tr>';
  88.   }
  89. }
  90.  
  91. // Helpers
  92.  
  93.  
  94. // Generate past N days in YYYY-MM-DD
  95. function getPastDates(days) {
  96.   const dates = [];
  97.   const today = new Date();
  98.   for (let i = 0; i < days; i++) {
  99.     const d = new Date(today);
  100.     d.setDate(today.getDate() - i);
  101.     dates.push(formatDateee(d));
  102.   }
  103.   return dates;
  104. }
  105.  
  106. // Generate all days of given month name
  107. function getMonthDates(monthName) {
  108.   const monthIndex = new Date(`${monthName} 1, ${new Date().getFullYear()}`).getMonth();
  109.   const year = new Date().getFullYear();
  110.   const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
  111.   const dates = [];
  112.   for (let i = 1; i <= daysInMonth; i++) {
  113.     dates.push(formatDateee(new Date(year, monthIndex, i)));
  114.   }
  115.   return dates;
  116. }
  117.  
  118. // Format date to YYYY-MM-DD
  119. function formatDateee(date) {
  120.   const year = date.getFullYear();
  121.   const month = String(date.getMonth() + 1).padStart(2, '0');
  122.   const day = String(date.getDate()).padStart(2, '0');
  123.   return `${year}-${month}-${day}`;
  124. }
  125.  
  126.  
  127.  
  128. //end of eod
  129.  
  130.             document.title = `{{ project_detail.project_name}}`;
  131.             // Add this to your existing script section
  132.             document.addEventListener('DOMContentLoaded', () => {
  133.                 const clientView = "{{ client_view }}" === "True";
  134.                 if (clientView) {
  135.                     // Disable all clickable elements
  136.                     document.querySelectorAll('button, input[type="checkbox"], .add-task-btn, .edit-btn').forEach(element => {
  137.                         element.style.pointerEvents = 'none';
  138.                         if (element.tagName === 'BUTTON') {
  139.                             element.disabled = true;
  140.                         }
  141.                     });
  142.  
  143.                     // Disable drag and drop
  144.                     document.querySelectorAll('[draggable="true"]').forEach(element => {
  145.                         element.draggable = false;
  146.                     });
  147.  
  148.                     // Make all form inputs readonly
  149.                     document.querySelectorAll('input, textarea, select').forEach(element => {
  150.                         element.readOnly = true;
  151.                         if (element.tagName === 'SELECT') {
  152.                             element.disabled = true;
  153.                         }
  154.                     });
  155.  
  156.                     // Keep task display toggle functionality
  157.                     document.querySelectorAll('.arrow-svg').forEach(arrow => {
  158.                         arrow.style.pointerEvents = 'auto';
  159.                         arrow.style.cursor = 'pointer';
  160.                     });
  161.  
  162.                     // Keep filter dropdown functional
  163.                     const taskFilterDropdown = document.getElementById('taskDropdown');
  164.                     if (taskFilterDropdown) {
  165.                         taskFilterDropdown.disabled = false;
  166.                         taskFilterDropdown.style.pointerEvents = 'auto';
  167.                     }
  168.  
  169.                     // Prevent default on all interactive elements except allowed ones
  170.                     document.addEventListener('click', (event) => {
  171.                         const allowedElements = ['.arrow-svg', '#taskDropdown'];
  172.                         const isAllowed = allowedElements.some(selector =>
  173.                             event.target.matches(selector) || event.target.closest(selector)
  174.                         );
  175.                        
  176.                         if (!isAllowed) {
  177.                             event.preventDefault();
  178.                         }
  179.                     }, true);
  180.  
  181.                     // Add visual indication of read-only state
  182.                     document.querySelectorAll('.task-row, .subtask-row').forEach(row => {
  183.                         row.style.cursor = 'default';
  184.                     });
  185.  
  186.                     // Disable all modals and popups
  187.                     const originalShowModal = window.showModal;
  188.                     window.showModal = function() {
  189.                         return false;
  190.                     };
  191.                 }
  192.             });
  193.  
  194.             // Update existing functions to check for client view before executing
  195.             const wrapWithClientCheck = (fn) => {
  196.                 return function(...args) {
  197.                     const clientView = "{{ client_view }}" === "True";
  198.                     if (clientView) {
  199.                         return false;
  200.                     }
  201.                     return fn.apply(this, args);
  202.                 };
  203.             };
  204.  
  205.             // Wrap all interactive functions
  206.             addTaskRow = wrapWithClientCheck(addTaskRow);
  207.             addSubtaskRow = wrapWithClientCheck(addSubtaskRow);
  208.             editTask = wrapWithClientCheck(editTask);
  209.             deleteTask = wrapWithClientCheck(deleteTask);
  210.             updateTaskStatus = wrapWithClientCheck(updateTaskStatus);
  211.             openAssigneeDropdown = wrapWithClientCheck(openAssigneeDropdown);
  212.             openDueDateDropdown = wrapWithClientCheck(openDueDateDropdown);
  213.             openPriorityDropdown = wrapWithClientCheck(openPriorityDropdown);
  214.             openBountyDropdown = wrapWithClientCheck(openBountyDropdown);
  215.             updateProjectStatus = wrapWithClientCheck(updateProjectStatus);
  216.             openTaskModal = wrapWithClientCheck(openTaskModal);
  217.             drag = wrapWithClientCheck(drag);
  218.             drop = wrapWithClientCheck(drop);
  219.             allowDrop = wrapWithClientCheck(allowDrop);
  220.  
  221.             function getCookie(name) {
  222.                 let cookieValue = null;
  223.                 if (document.cookie && document.cookie !== '') {
  224.                     const cookies = document.cookie.split(';');
  225.                     for (let i = 0; i < cookies.length; i++) {
  226.                         const cookie = cookies[i].trim();
  227.                         if (cookie.substring(0, name.length + 1) === (name + '=')) {
  228.                             cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  229.                             break;
  230.                         }
  231.                     }
  232.                 }
  233.                 return cookieValue;
  234.             }
  235.        
  236.             const csrftoken = getCookie('csrftoken');
  237.        
  238.             if (!csrftoken) {
  239.                 console.error('CSRF token not found!');
  240.             }
  241.  
  242.  
  243.             const projectId = "{{ project_detail.id }}";
  244.             const replacementMembers = {{ replacements| safe }};
  245.             const team_members = {{ team_members | safe}};
  246.             const milestoneStatuses = {{ milestone_statuses | safe }};
  247.             const notifications = "{{notifs}}";
  248.             const roles = {{ roles |safe }};
  249.             let currentUserId = '';
  250.             const members = {{ team_members | safe }};
  251.             let filtered = "pending";
  252.             const zoom = 1;
  253.             let milestoneCount = Object.keys(milestoneStatuses).length;
  254.  
  255.             // Maintain a reference to the currently active dropdown
  256.             let activeDropdown = null;
  257.  
  258.             // function pdhActive(elem) {
  259.             //     // Check if the clicked element is already active
  260.             //     if (activeDropdown === elem) {
  261.             //         elem.classList.remove('active-pdh'); // Close the active dropdown
  262.             //         activeDropdown = null; // Reset the activeDropdown reference
  263.             //     } else {
  264.             //         // Close any previously active dropdown
  265.             //         if (activeDropdown) {
  266.             //             activeDropdown.classList.remove('active-pdh');
  267.             //         }
  268.                
  269.             //         // Open the new dropdown
  270.             //         elem.classList.add('active-pdh');
  271.             //         activeDropdown = elem; // Update the activeDropdown reference
  272.             //     }
  273.             // }
  274. let elem1;
  275.             function pdhActive(elem) {
  276.                 let activeDropdown = null;
  277.  
  278.                 function handleDocumentClick(event) {
  279.                     elem1=event.target
  280.                     if (event.target === elem || elem.contains(event.target) && event.target.closest('svg')) {
  281.                         if (activeDropdown === elem) {
  282.                             elem.classList.remove('active-pdh');
  283.                             activeDropdown = null;
  284.                             document.removeEventListener('click', handleDocumentClick);
  285.                         } else {
  286.                             if (activeDropdown) {
  287.                                 activeDropdown.classList.remove('active-pdh');
  288.                             }
  289.                             elem.classList.add('active-pdh');
  290.                             activeDropdown = elem;
  291.                         }
  292.                     } else if (!event.target.closest('.pdh-doc-dd')) {
  293.                         // If clicked outside the dropdown, close the dropdown
  294.                         if (activeDropdown) {
  295.                             activeDropdown.classList.remove('active-pdh');
  296.                             activeDropdown = null;
  297.                             document.removeEventListener('click', handleDocumentClick);
  298.                         }
  299.                     }
  300.                 }
  301.                 document.addEventListener('click', handleDocumentClick);
  302.             }
  303.  
  304.             // Add an event listener to handle clicks outside the dropdowns
  305.             document.addEventListener('click', (event) => {
  306.                 if (
  307.                     activeDropdown &&
  308.                     !activeDropdown.contains(event.target) && // Check if the click is outside the dropdown
  309.                     !event.target.closest('.dropdown-trigger') // Allow clicks on elements that trigger the dropdown
  310.                 ) {
  311.                     activeDropdown.classList.remove('active-pdh'); // Close the active dropdown
  312.                     activeDropdown = null; // Reset the activeDropdown reference
  313.                 }
  314.             });
  315.  
  316.             function openThisDd(elem) {
  317.                 const dropdown = elem.querySelector(".sub-drop-down");
  318.                 const typeLabel = elem.querySelector('.milestone-type-block');
  319.  
  320.                 // Function to handle document clicks
  321.                 function handleDocumentClick(event) {
  322.                     if (!elem.contains(event.target)) {
  323.                         dropdown.classList.remove("active-dd");
  324.                         document.removeEventListener("click", handleDocumentClick);
  325.                     }
  326.                 }
  327.  
  328.                 // Toggle the dropdown
  329.                 const isActive = dropdown.classList.toggle("active-dd");
  330.  
  331.                 // Add click handlers to the options
  332.                 const options = dropdown.querySelectorAll('.sub-dd-opt');
  333.                 options.forEach(option => {
  334.                     option.onclick = (e) => {
  335.                         e.stopPropagation();
  336.                         typeLabel.textContent = option.textContent;
  337.                         typeLabel.dataset.value = option.dataset.value;
  338.                         dropdown.classList.remove("active-dd");
  339.                     };
  340.                 });
  341.  
  342.                 if (isActive) {
  343.                     document.addEventListener("click", handleDocumentClick);
  344.                 } else {
  345.                     document.removeEventListener("click", handleDocumentClick);
  346.                 }
  347.             }
  348.  
  349.             function pinUnpinDoc(elem) {
  350.                 const docElem = elem.closest(".mdoc-document-list-content");
  351.                 const projectId = elem.dataset.projectId;
  352.                 const documentName = elem.dataset.documentName;
  353.                 const documentUrl = elem.dataset.documentUrl;
  354.  
  355.                 fetch('/project/toggle-pin-document/', {
  356.                     method: 'POST',
  357.                     headers: {
  358.                         'Content-Type': 'application/json',
  359.                         'X-CSRFToken': '{{ csrf_token }}',
  360.                     },
  361.                     body: JSON.stringify({
  362.                         project_id: projectId,
  363.                         document_name: documentName,
  364.                         document_url: documentUrl
  365.                     })
  366.                 })
  367.                 .then(response => response.json())
  368.                 .then(data => {
  369.                     if (data.status === 'success') {
  370.                         // Update UI based on server response
  371.                         docElem.setAttribute("data-pinned", data.pinned);
  372.                        
  373.                         // Update the Pin/Unpin text
  374.                         elem.textContent = data.pinned ? "Unpin Document" : "Pin Document";
  375.  
  376.                         // Update pin icon visibility
  377.                         const pinIconContainer = elem.closest(".doc-list-opt-dd").parentElement.lastElementChild;
  378.                         if (pinIconContainer) {
  379.                             pinIconContainer.style.display = data.pinned ? "block" : "none";
  380.                         }
  381.  
  382.                         // Sort documents
  383.                         const documentList = docElem.closest('.mdoc-document-list');
  384.                         if (documentList) {
  385.                             const documents = Array.from(documentList.children);
  386.                             documents.sort((a, b) => {
  387.                                 const aPinned = a.getAttribute("data-pinned") === "true";
  388.                                 const bPinned = b.getAttribute("data-pinned") === "true";
  389.                                
  390.                                 if (aPinned !== bPinned) {
  391.                                     return bPinned ? 1 : -1;
  392.                                 }
  393.                                
  394.                                 const aDate = parseDateFromString(a.getAttribute("data-created"));
  395.                                 const bDate = parseDateFromString(b.getAttribute("data-created"));
  396.                                 return bDate - aDate;
  397.                             });
  398.  
  399.                             // Clear and repopulate the list
  400.                             while (documentList.firstChild) {
  401.                                 documentList.removeChild(documentList.firstChild);
  402.                             }
  403.                             documents.forEach(doc => documentList.appendChild(doc));
  404.                         }
  405.  
  406.                         // Close the dropdown
  407.                         const dropdown = elem.closest(".sub-drop-down");
  408.                     } else {
  409.                         console.error("Failed to update pin status:", data.message);
  410.                     }
  411.                 })
  412.                 .catch(error => {
  413.                     console.error("Error updating pin status:", error);
  414.                 });
  415.             }
  416.             function parseDateFromString(dateString) {
  417.                 if (!dateString) return new Date(0); // Return oldest possible date if no date string
  418.                 const [day, month, year] = dateString.split("/").map(Number);
  419.                 return new Date(2000 + year, month - 1, day);
  420.             }
  421.  
  422.  
  423.             function updateProjectStatus(proj_status, project_id){
  424.                 let status_name = {
  425.                     "on_track": {
  426.                         name: "On track",
  427.                         color: "#00B879",
  428.                     },
  429.                     "escalated": {
  430.                         name: "Escalated",
  431.                         color: "#A90420",
  432.                     },
  433.                 }
  434.                 fetch(`/api/update-priority/${project_id}/`, {
  435.                     method: 'PUT',
  436.                     headers: {
  437.                       'Content-Type': 'application/json',
  438.                       'X-CSRFToken': csrftoken,
  439.                     },
  440.                     body: JSON.stringify({status: proj_status}),
  441.                     credentials: "include",
  442.                 })
  443.                 .then((response) => {
  444.                   if (!response.ok) {
  445.                     throw new Error('API call failed');
  446.                   }
  447.                   return response.json();
  448.                 })
  449.                 .then((data) => {
  450.                     let project_status_cont = document.querySelector("#project-status").innerHTML=`
  451.                         <div style="border-radius: 100%; width: 14px; height: 14px; background-color: ${status_name[proj_status].color};"></div>
  452.                          ${status_name[proj_status].name}
  453.                     `
  454.                   console.log('API response:', data);
  455.                 })
  456.                 .catch((error) => {
  457.                   console.error('Error:', error);
  458.                 });
  459.             }
  460.            
  461.             function openPriorityDd(elem) {
  462.                 // Instead of opening a dropdown, we will just toggle the priority
  463.                 let currentPriority = elem.closest('div').querySelector("span").innerText;
  464.  
  465.                 // Set the next priority
  466.                 let nextPriority;
  467.                 switch (currentPriority) {
  468.                     case "P1":
  469.                         nextPriority = "P2";
  470.                         break;
  471.                     case "P2":
  472.                         nextPriority = "P3";
  473.                         break;
  474.                     case "P3":
  475.                         nextPriority = "P1";
  476.                         break;
  477.                     default:
  478.                         nextPriority = "P1"; // Default to P1 if something is wrong
  479.                         break;
  480.                 }
  481.  
  482.                 // Update the UI immediately
  483.                 elem.closest('div').querySelector("span").innerText = nextPriority;
  484.                 switch (nextPriority) {
  485.                     case "P1":
  486.                         elem.closest('div').style.fontWeight='bolder'
  487.                         elem.closest('div').style.borderColor='#94999d'
  488.                         break;
  489.                     case "P2":
  490.                         elem.closest('div').style.fontWeight='600'
  491.                         elem.closest('div').style.borderColor='#99a4ad'
  492.                         break;
  493.                     case "P3":
  494.                         elem.closest('div').style.fontWeight='400'
  495.                         elem.closest('div').style.borderColor='#CED4DA'
  496.                         break;
  497.                     default:
  498.                         break;
  499.                 }
  500.  
  501.                 // Get project_id from the closest div or from data-attribute if needed
  502.                 let project_id = elem.getAttribute("data-project-id");
  503.  
  504.                 // Call the function to update priority in the backend
  505.                 setPriority(nextPriority, project_id, elem);
  506.             }
  507.  
  508.             function setPriority(priority, project_id, elem) {
  509.                 // Convert the priority to the corresponding string value (P1, P2, P3)
  510.                 let p;
  511.                 switch (priority) {
  512.                     case "P1":
  513.                         p = "P1";
  514.                         break;
  515.                     case "P2":
  516.                         p = "P2";
  517.                         break;
  518.                     case "P3":
  519.                         p = "P3";
  520.                         break;
  521.                     default:
  522.                         p = null;
  523.                         break;
  524.                 }
  525.            
  526.                 // Make the API call to update the priority in the database
  527.                 fetch(`/api/update-priority/${project_id}/`, {
  528.                     method: 'PUT',
  529.                     headers: {
  530.                         'Content-Type': 'application/json',
  531.                         'X-CSRFToken': csrftoken,
  532.                     },
  533.                     body: JSON.stringify({ priority: p }),
  534.                     credentials: "include",
  535.                 })
  536.                 .then((response) => {
  537.                     if (!response.ok) {
  538.                         throw new Error('API call failed');
  539.                     }
  540.                     return response.json();
  541.                 })
  542.                 .then((data) => {
  543.                     // Update the UI based on the response
  544.                     console.log('API response:', data);
  545.                 })
  546.                 .catch((error) => {
  547.                     console.error('Error:', error);
  548.                 });
  549.             }
  550.  
  551.  
  552.             //end project function
  553.             async function endProject(element){
  554.                 try {
  555.                    
  556.                     const teamMembersResponse = await fetch(`/api/project/${element.id}/team-members/`, {
  557.                         method: 'GET',
  558.                         headers: {
  559.                             'Content-Type': 'application/json',
  560.                         },
  561.                     });
  562.  
  563.                     if (!teamMembersResponse.ok) {
  564.                         throw new Error('Failed to fetch team members');
  565.                     }
  566.  
  567.                     const teamMembersData = await teamMembersResponse.json();
  568.  
  569.                    
  570.                     if (teamMembersData.length > 0) {
  571.                         alert('Cannot end the project. Please remove all team members first.');
  572.                         return;
  573.                     }
  574.  
  575.                    
  576.                     const updateStatusResponse = await fetch(`/api/update-priority/${element.id}/`, {
  577.                         method: 'PUT',
  578.                         headers: {
  579.                             'Content-Type': 'application/json',
  580.                             'X-CSRFToken': csrftoken,
  581.                         },
  582.                         body: JSON.stringify({ status: "ended" }),
  583.                     });
  584.  
  585.                     if (!updateStatusResponse.ok) {
  586.                         throw new Error('Failed to update project status');
  587.                     }
  588.  
  589.                     const updateStatusData = await updateStatusResponse.json();
  590.                     alert( 'Project ended successfully!');
  591.                    
  592.                 } catch (error) {
  593.                     console.error('Error:', error);
  594.                     alert('An error occurred. Please try again later.');
  595.                 }
  596.             }
  597.            
  598.             function addTeamMemberAgain(button) {
  599.            
  600.                 const memberId = button.closest('tr').id;
  601.            
  602.                
  603.                 const data = {
  604.                     member_id: memberId,
  605.                     project_id: projectId,
  606.                 };
  607.        
  608.                 fetch('/project/addMemberBack/', {
  609.                     method: 'POST',
  610.                     headers: {
  611.                         'Content-Type': 'application/json',
  612.                     },
  613.                     body: JSON.stringify(data),
  614.                 })
  615.                 .then(response => {
  616.                     if (response.ok) {
  617.                         return response.json();
  618.                     }
  619.                     throw new Error('Network response was not ok.');
  620.                 })
  621.                 .then(data => {
  622.                     // Handle success, e.g., update the UI or show a message
  623.                     console.log('Success:', data);
  624.                     window.location.reload();
  625.                 })
  626.                 .catch((error) => {
  627.                     alert(response.json);
  628.                     console.error('Error:', error);
  629.                 });
  630.             }
  631.             function toggleCategory(element) {
  632.                 const category = element.parentElement;
  633.                 category.classList.toggle('expanded');
  634.             }
  635.            
  636.             function projectNotifClose() {
  637.                 const notifDiv = document.querySelector(".project-notifications-content");
  638.                 const notifAlert = document.querySelector(".notif-reddot");
  639.                 const arrow = document.getElementById('notif-chevron-icon');
  640.                 const arrowPath = arrow.querySelector('path');
  641.                 if (notifDiv.style.display === "block" || notifDiv.style.display === "") {
  642.                     notifDiv.style.display = "none";
  643.                     if (notifications=="True"){  
  644.                         notifAlert.style.display = "block"
  645.                     }
  646.                        
  647.                    
  648.                     arrowPath.setAttribute('d', 'M1 1L7 7L13 1');
  649.                 } else {
  650.                     notifDiv.style.display = "block";
  651.                     notifAlert.style.display = "none"
  652.                     arrowPath.setAttribute('d', 'M13 7L7 1L1 7');
  653.                 }
  654.             }
  655.             function mdocToggleExpand() {
  656.                 const contentDiv = document.querySelector('.mdoc-content-div');
  657.                 const arrow = document.getElementById('mdoc-chevron-icon');
  658.                 const arrowPath = arrow.querySelector('path');
  659.                 if (contentDiv.style.display === "none" || contentDiv.style.display === "") {
  660.                     contentDiv.style.display = "block";
  661.                     arrowPath.setAttribute('d', 'M13 7L7 1L1 7');
  662.                 } else {
  663.                     contentDiv.style.display = "none";
  664.                     arrowPath.setAttribute('d', 'M1 1L7 7L13 1');
  665.                 }
  666.             }
  667.             function keyProjectExpand() {
  668.                 const viewModeDiv = document.getElementById('view-mode');
  669.                 const editModeDiv = document.getElementById('edit-mode');
  670.                 const arrow = document.getElementById('projectKey-details-chevron-icon');
  671.                 const arrowPath = arrow.querySelector('path');
  672.                 if (viewModeDiv.style.display === "none" || viewModeDiv.style.display === "") {
  673.                     viewModeDiv.style.display = "flex";
  674.                     editModeDiv.style.display = "none";
  675.                     arrowPath.setAttribute('d', 'M13 7L7 1L1 7');
  676.                 } else {
  677.                     viewModeDiv.style.display = "none";
  678.                     arrowPath.setAttribute('d', 'M1 1L7 7L13 1');
  679.                 }
  680.             }
  681.  
  682.             let currentNotifId = null;
  683.  
  684.             /* SNOOZING NOTIFS */
  685.             function toggleSnoozeDropdown(button) {
  686.                 const dropdown = button.parentElement.querySelector('.snooze-dropdown');
  687.  
  688.                 if (dropdown.style.display === "flex") {
  689.                     dropdown.style.display = "none";
  690.                 } else {
  691.                    
  692.                     document.querySelectorAll('.snooze-dropdown').forEach(drop => drop.style.display = 'none');
  693.                     dropdown.style.display = "flex";
  694.                     const rect = button.getBoundingClientRect();
  695.                     dropdown.style.top = `${(rect.top + window.scrollY + button.offsetHeight)/zoom}px`;
  696.                     dropdown.style.left = `${(rect.left + window.scrollX)/zoom}px`;
  697.                 }
  698.             }
  699.            
  700.             function closeSnoozeDropdown(closeBtn) {
  701.                 const dropdown = closeBtn.parentElement;
  702.                 dropdown.style.display = "none";
  703.             }
  704.  
  705.             function confirmSnooze(notifId) {
  706.                 const dropdown = document.querySelector(`#notif-${notifId} .snooze-dropdown`);
  707.                 const days = dropdown.querySelector('.snooze-select').value;
  708.            
  709.                 // Fetch to backend to handle snoozing logic
  710.                 fetch(`/snooze_notification/`, {
  711.                     method: 'POST',
  712.                     headers: {
  713.                         'Content-Type': 'application/json',
  714.                     },
  715.                     body: JSON.stringify({
  716.                         notif_id: notifId,
  717.                         snooze_days: days
  718.                     }),
  719.                 })
  720.                 .then(response => response.json())
  721.                 .then(data => {
  722.                     if (data.success) {
  723.                         // Remove the notification from frontend
  724.                         const notifElement = document.getElementById(`notif-${notifId}`);
  725.                         if (notifElement) {
  726.                             notifElement.remove();
  727.                         }
  728.                     }
  729.                 })
  730.                 .catch(error => console.error('Error:', error));
  731.             }
  732.        
  733.             /* NOTIF HANDLING */
  734.             function selectSortButton(button, type, criteria) {
  735.                 document.querySelectorAll('.sort-button').forEach(btn => btn.classList.remove('selected'));
  736.                 button.classList.add('selected');
  737.                 sortNotifications(type, criteria);
  738.             }
  739.  
  740.             function toggleDropdown() {
  741.         var dropdown = document.getElementById("hat-dropdown");
  742.         if (dropdown.style.opacity == '0' ||  dropdown.style.opacity === "") {
  743.             dropdown.classList.add("visible")
  744.             dropdown.style.transform = "scaleY(1)";  
  745.         } else {
  746.             dropdown.classList.remove("visible")
  747.             dropdown.style.transform = "scaleY(0)";
  748.         }
  749.     }
  750.    
  751.     function addHat(hatType) {
  752.  
  753.         const row = Number(currentUserId);
  754.  
  755.         const hatIcon = document.querySelector(`#hat-icon-${row}`);
  756.  
  757.  
  758.         if (!hatIcon) {
  759.             console.error(`No element found with ID: #hat-icon-${row}`);
  760.             return;
  761.         }
  762.  
  763.         const existingHat = hatIcon.querySelector('svg').children[0].getAttribute('fill');
  764.         if (existingHat != 'none') {
  765.             alert("This user already has a hat.");
  766.             return;
  767.         }
  768.  
  769.         let fillColor, tooltipText;
  770.         if (hatType === 'projectManager') {
  771.             fillColor = '#504CF5';
  772.             tooltipText = 'Project Manager';
  773.         } else if (hatType === 'devops') {
  774.             fillColor = '#1EB88A';
  775.             tooltipText = 'DevOps';
  776.         } else {
  777.             console.error(`Invalid hatType: ${hatType}`);
  778.             return;
  779.         }
  780.  
  781.         const hatSvg = `
  782.             <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
  783.                 <path fill-rule="evenodd" clip-rule="evenodd" d="M15.885 10.0762C15.3475 11.2224 13.185 12.6112 10 12.6112C6.835 12.6112 4.58375 11.2399 4.11 10.0949C1.71875 10.2024 0 11.6324 0 12.4824C0 13.8924 4.47625 15.8924 10 15.8924C15.5225 15.8924 20 13.8924 20 12.4824C20 11.6212 18.2812 10.5237 15.885 10.0762Z" fill="${fillColor}"/>
  784.                 <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5964 3.80859C11.9514 3.80859 10.6189 4.25109 10.0151 4.25109C9.41137 4.25109 8.07887 3.80859 7.43512 3.80859C6.04262 3.80859 5.17262 5.52359 5.05137 6.17984L5.02637 9.21359C5.72887 9.84609 7.04012 10.6411 8.47762 10.7611C8.97762 10.8023 9.50512 10.8273 10.0539 10.8273C10.6001 10.8273 11.1264 10.8023 11.6276 10.7611C13.0651 10.6398 14.2201 9.94359 14.9626 9.23484L14.9564 6.21859C14.8489 5.53609 13.9764 3.80859 12.5964 3.80859Z" fill="${fillColor}"/>
  785.             </svg>
  786.         `;
  787.  
  788.         hatIcon.innerHTML = `
  789.             <div class="hat-container" style="position: relative; display: inline-block;">
  790.                 ${hatSvg}
  791.                 <span class="hat-tooltip" style="display: none; position: absolute; bottom: 125%; left: 50%; transform: translateX(-50%); padding: 6px 12px; background: black; color: white; border-radius: 4px; white-space: nowrap; font-size: 12px;">
  792.                     ${tooltipText}
  793.                 </span>
  794.             </div>
  795.         `;
  796.  
  797.         fetch('/project/updateHat/', {
  798.             method: 'POST',
  799.             headers: {
  800.                 'Content-Type': 'application/json'
  801.             },
  802.             body: JSON.stringify({
  803.                 memberId: row,
  804.                 hatType: hatType,
  805.                 projectId : projectId
  806.             })
  807.         })
  808.         .then(response => response.json())
  809.         .then(data => {
  810.             console.log('Hat updated successfully:', data);
  811.         })
  812.         .catch(error => {
  813.             console.error('Error updating hat:', error);
  814.         });
  815.  
  816.         const hatContainer = hatIcon.querySelector('.hat-container');
  817.         const tooltip = hatIcon.querySelector('.hat-tooltip');
  818.  
  819.         hatContainer.addEventListener('mouseenter', () => {
  820.             tooltip.style.display = 'block';
  821.         });
  822.  
  823.         hatContainer.addEventListener('mouseleave', () => {
  824.             tooltip.style.display = 'none';
  825.         });
  826.     }
  827.  
  828. function removeHat() {
  829.     const row = Number(currentUserId);
  830.  
  831.     const hatIcon = document.querySelector(`#hat-icon-${row}`);
  832.  
  833.     if (!hatIcon) {
  834.         console.error(`No element found with ID: #hat-icon-${row}`);
  835.         return;
  836.     }
  837.  
  838.     const existingHat = hatIcon.querySelector('svg');
  839.     if (existingHat) {
  840.         hatIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
  841.                                             <path fill-rule="evenodd" clip-rule="evenodd" d="M15.885 10.0762C15.3475 11.2224 13.185 12.6112 10 12.6112C6.835 12.6112 4.58375 11.2399 4.11 10.0949C1.71875 10.2024 0 11.6324 0 12.4824C0 13.8924 4.47625 15.8924 10 15.8924C15.5225 15.8924 20 13.8924 20 12.4824C20 11.6212 18.2812 10.5237 15.885 10.0762Z" fill="none"/>
  842.                                             <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5964 3.80859C11.9514 3.80859 10.6189 4.25109 10.0151 4.25109C9.41137 4.25109 8.07887 3.80859 7.43512 3.80859C6.04262 3.80859 5.17262 5.52359 5.05137 6.17984L5.02637 9.21359C5.72887 9.84609 7.04012 10.6411 8.47762 10.7611C8.97762 10.8023 9.50512 10.8273 10.0539 10.8273C10.6001 10.8273 11.1264 10.8023 11.6276 10.7611C13.0651 10.6398 14.2201 9.94359 14.9626 9.23484L14.9564 6.21859C14.8489 5.53609 13.9764 3.80859 12.5964 3.80859Z" fill="none"/>
  843.                                         </svg>
  844.                                         <span class="hat-tooltip" style="display: none; position: absolute; bottom: 125%; left: 50%; transform: translateX(-50%); padding: 6px 12px; background: black; color: white; border-radius: 4px; white-space: nowrap; font-size: 12px;">
  845.                                             DevOps
  846.                                         </span>`;
  847.     } else {
  848.         alert("This user doesn't have a hat assigned.");
  849.     }
  850.     fetch('/project/removeHat/', {
  851.         method: 'POST',
  852.         headers: {
  853.             'Content-Type': 'application/json'
  854.         },
  855.         body: JSON.stringify({
  856.             memberId: row,
  857.             projectId : projectId
  858.         })
  859.     })
  860.     .then(response => response.json())
  861.     .then(data => {
  862.         console.log('Hat removed successfully:', data);
  863.     })
  864.     .catch(error => {
  865.         console.error('Error removing hat:', error);
  866.     });
  867. }
  868.  
  869.  
  870.            
  871.             function sortNotifications(type, criteria) {
  872.                 const notificationList = document.getElementById(`${type}-category`);
  873.                 const notifications = Array.from(notificationList.getElementsByClassName('notif-container'));
  874.            
  875.                 notifications.sort((a, b) => {
  876.                     const aValue = a.getAttribute(`data-${criteria}`).toLowerCase();
  877.                     const bValue = b.getAttribute(`data-${criteria}`).toLowerCase();
  878.                     return aValue.localeCompare(bValue);
  879.                 });
  880.            
  881.                
  882.                 notifications.forEach((notif, index) => {
  883.                     notif.style.order = index;
  884.                 });
  885.             }
  886.            
  887.             function handleNotificationClick(event,notifId) {
  888.                 event.preventDefault();
  889.                
  890.                
  891.                     fetch(`/project/notifications_read/`, {
  892.                         method: 'POST',
  893.                         headers: {
  894.                            
  895.                             'Content-Type': 'application/json',
  896.                         },
  897.                         body: JSON.stringify({
  898.                             notif_id : notifId
  899.                         }),
  900.                     })
  901.                     .then(response => response.json())
  902.                     .then(data => {
  903.                         if (data.success) {
  904.                             const notifElement = document.getElementById(`notif-${notifId}`);
  905.                             if (notifElement) {
  906.                                 notifElement.remove();
  907.                             }
  908.                            
  909.                            
  910.                         }
  911.                     })
  912.                     .catch(error => console.error('Error:', error));
  913.                 }  
  914.            
  915.             /* MISSING KT */
  916.            
  917.             function toggleModal(userId) {
  918.                 const modal = document.getElementById("ktLinkModal");
  919.                 currentUserId = userId; // Store the user ID when the modal opens
  920.                 modal.style.display = modal.style.display === "flex" ? "none" : "flex";
  921.             }
  922.            
  923.             function submitKTlink() {
  924.                 const ktLink = document.getElementById("p-ktLink").value;
  925.            
  926.                 if (!ktLink) {
  927.                     alert("Please enter a KT link.");
  928.                     return;
  929.                 }
  930.          
  931.            
  932.                 fetch('/project/add_ktlink/', {
  933.                     method: 'POST',
  934.                     headers: {
  935.                         'Content-Type': 'application/json'
  936.                        
  937.                     },
  938.                     body: JSON.stringify({
  939.                         user_id: currentUserId,
  940.                         kt_link: ktLink,
  941.                         project_id: projectId
  942.                     })
  943.                 })
  944.                 .then(response => response.json())
  945.                 .then(data => {
  946.                     if (data.status === 'success') {
  947.                         alert('KT link added successfully!');
  948.                         const modal = document.getElementById("ktLinkModal");
  949.                         modal.style.display = "none";
  950.                         window.location.reload();
  951.                     } else {
  952.                         alert('Error: ' + data.message);
  953.                     }
  954.                 })
  955.                 .catch(error => {
  956.                     console.error('Error:', error);
  957.                 });
  958.             }
  959.            
  960.             /* TEAMMEMBER EDITS */
  961.  
  962.             function addTeamMember() {
  963.                 event.preventDefault(); // Prevent the default form submission behavior
  964.                 const tbody = document.getElementById('team-members-tbody'); // Get the tbody element
  965.                 const tr = document.createElement('tr'); // Create a new table row
  966.                 tr.style.textAlign = 'left'; // Set text alignment
  967.                 tr.setAttribute('id', 'add-tr'); // Set an ID for the row
  968.            
  969.                 tr.innerHTML = `
  970.                     <td>
  971.                         <select class="user-select select-dropdown" name="selected_user_id" onchange="updateMemberDetails(this)">
  972.                             <option value="">Select Name</option>
  973.                             ${replacementMembers.map(member => `<option value="${member.id}">${member.name}</option>`).join('')}
  974.                         </select>
  975.                     </td>
  976.                     <td id="role-column">
  977.                         <select class="role-select select-dropdown" name="role" onchange="updateUserSelect(this)">
  978.                             <option value="all">Select Role</option>
  979.                             ${roles.map(role => `<option value="${role.name}">${role.name}</option>`).join('')}
  980.                         </select>
  981.                     </td>
  982.                     <td id="availability-column">
  983.                         <input type="text" name="availability" placeholder="Available" />
  984.                     </td>
  985.                     <td id="contact-column">
  986.                         <div>Email: <input type="email" name="email" placeholder="Email" /></div>
  987.                         <div>Mob: <input type="tel" name="mobile" placeholder="Mobile" /></div>
  988.                     </td>
  989.                     <td>
  990.                         <span class="delete-icon" onclick="deleteRow(this)">&#10006;</span>
  991.                     </td>
  992.                     <td>
  993.                         <button type="button" class="key-project-save-btn" onclick="saveMember(this)">Save</button>
  994.                     </td>
  995.                 `;
  996.                 tbody.appendChild(tr); // Append the new row to the tbody
  997.                 $(tr).find('.user-select, .role-select').select2();
  998.                
  999.             }
  1000.  
  1001.             function updateUserSelect(roleSelect) {
  1002.                 const selectedRoleId = roleSelect.value;
  1003.                 const userSelect = roleSelect.closest('tr').querySelector('.user-select');
  1004.                 userSelect.innerHTML = '<option value="">Select Name</option>';
  1005.                 if (selectedRoleId !="all") {
  1006.                    
  1007.                     const filteredMembers = replacementMembers.filter(member => member.department== selectedRoleId);
  1008.                     userSelect.innerHTML += filteredMembers.map(member => `<option value="${member.id}">${member.name}</option>`).join('');
  1009.                    
  1010.                 }
  1011.                 else{
  1012.                     userSelect.innerHTML += replacementMembers.map(member => `<option value="${member.id}">${member.name}</option>`).join('');
  1013.                 }
  1014.                 $(userSelect).select2();
  1015.             }
  1016.            
  1017.  
  1018.             function deleteRow(button) {
  1019.                 const row = button.closest('tr');
  1020.                 row.remove();
  1021.             }
  1022.  
  1023.             function saveMember(button) {
  1024.  
  1025.                 const row = button.closest('tr');
  1026.  
  1027.  
  1028.                 const select = row.querySelector('select[name="selected_user_id"]');
  1029.                 const selectedUserId = select.value;
  1030.  
  1031.  
  1032.                 if (!selectedUserId) {
  1033.                     alert('Please select a user.');
  1034.                     return;
  1035.                 }
  1036.  
  1037.  
  1038.                 const role = row.querySelector('#role-column').textContent.trim();
  1039.                 const availability = row.querySelector('#availability-column').textContent.trim();
  1040.                 const contactInfo = row.querySelector('#contact-column').innerText.trim();
  1041.  
  1042.                 const data = {
  1043.                     user_id: selectedUserId,
  1044.                     project_id: projectId
  1045.  
  1046.                 };
  1047.  
  1048.                
  1049.                 fetch('/project/addMember/', {
  1050.                     method: 'POST',
  1051.                     headers: {
  1052.                         'Content-Type': 'application/json',
  1053.  
  1054.                     },
  1055.                     body: JSON.stringify(data)
  1056.                 })
  1057.                     .then(response => response.json())
  1058.                     .then(result => {
  1059.                         if (result.success) {
  1060.                             alert('Member saved successfully!');
  1061.                             window.location.reload();
  1062.                         } else {
  1063.                             alert('Failed to save member.');
  1064.                         }
  1065.                     })
  1066.                     .catch(error => {
  1067.                         console.error('Error:', error);
  1068.                         alert('An error occurred while saving the member.');
  1069.                     });
  1070.             }
  1071.  
  1072.            
  1073.             //function for hide and show previous member
  1074.             function toggleMembers() {
  1075.                 const previousMembers = document.querySelectorAll('.team-members-previous-member');
  1076.                 const toggleButton = document.getElementById('toggle-members-btn');
  1077.  
  1078.  
  1079.                 if (previousMembers.length > 0 && previousMembers[0].style.display === 'none') {
  1080.                     // show previous members
  1081.                     previousMembers.forEach(row => row.style.display = '');
  1082.                     toggleButton.innerHTML = 'Hide Previous members <svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 7L7 1L1 7" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
  1083.                 } else {
  1084.                     // hide previous members
  1085.                     previousMembers.forEach(row => row.style.display = 'none');
  1086.                     toggleButton.innerHTML = `Show Previous members <svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  1087.                                                 <path d="M1 1L7 7L13 1" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  1088.                                             </svg>`;
  1089.                 }
  1090.             }
  1091.  
  1092.            
  1093.             function showPopup(event, userId) {
  1094.                 currentUserId = userId; //
  1095.                
  1096.                 const svg = event.currentTarget;
  1097.                 const popup = document.getElementById('team-member-action-popup');
  1098.                 var dropdown = document.getElementById("hat-dropdown");
  1099.  
  1100.                 // calculate position of the SVG element
  1101.                 const rect = svg.getBoundingClientRect();
  1102.                 const offsetX = window.scrollX;
  1103.                 const offsetY = window.scrollY;
  1104.  
  1105.                 // position the popup
  1106.                 popup.style.left = `${(rect.left + offsetX)/zoom}px`;
  1107.                 popup.style.top = `${(rect.bottom + offsetY)/zoom}px`;
  1108.                 popup.classList.toggle("visible")
  1109.  
  1110.                 // hide the popup when clicking outside of it
  1111.                 function handleClickOutside(event) {
  1112.                     if (!popup.contains(event.target) && !svg.contains(event.target)) {
  1113.                         popup.classList.remove('visible')
  1114.                         dropdown.classList.remove('visible')
  1115.                         dropdown.style.transform="scaleY(0)"
  1116.                         document.removeEventListener('click', handleClickOutside);
  1117.                     }
  1118.                 }
  1119.                 document.addEventListener('click', handleClickOutside);
  1120.             }
  1121.  
  1122.             document.addEventListener("click", function (event) {
  1123.         const dropdown = document.querySelector(".project-status-dd");
  1124.         const spanElement = event.target.closest("span");
  1125.        
  1126.         if (!dropdown.contains(event.target) && !spanElement) {
  1127.             // If the click is outside the dropdown and span element, remove the visible class
  1128.             dropdown.classList.remove("visible");
  1129.         }
  1130.     });
  1131.  
  1132.             function openReplaceModal() {
  1133.                 event.preventDefault();
  1134.                 const replaceModal = document.getElementById('replace-modal');
  1135.                 // const overlay = document.getElementById('overlay');
  1136.  
  1137.                 // populate the modal with data from the selected row
  1138.                 const row = document.getElementById(currentUserId);
  1139.                 const teamMemberNameElement = row.querySelector('.team-member-name');
  1140.                 const name = teamMemberNameElement.childNodes[0].textContent.trim();
  1141.                 const role = row.cells[1].textContent;
  1142.  
  1143.                 document.getElementById('replace-modal-role').textContent = `${role}: ${name}`;
  1144.  
  1145.                 // populate select options dynamically
  1146.                 const replaceSelect = document.getElementById('replace-select');
  1147.                 $(replaceSelect).select2();
  1148.                 replaceModal.style.display = 'block';
  1149.                 // overlay.style.display = 'block';
  1150.  
  1151.                 // Prevent closing modal when clicking inside
  1152.                 replaceModal.addEventListener('click', function (event) {
  1153.                     event.stopPropagation();
  1154.                 });
  1155.             }
  1156.  
  1157.             function closeReplaceModal() {
  1158.                 event.preventDefault();
  1159.                 const replaceModal = document.getElementById('replace-modal');
  1160.                 const overlay = document.getElementById('overlay');
  1161.  
  1162.                 replaceModal.style.display = 'none';
  1163.                 // overlay.style.display = 'none';
  1164.             }
  1165.  
  1166.             function replaceMember() {
  1167.                 event.preventDefault();
  1168.                 const replaceSelect = document.getElementById('replace-select').value;
  1169.                 const ktLink = document.getElementById('kt-link').value;
  1170.                 fetch('/project/replaceMember/', {
  1171.                     method: 'POST',
  1172.                     headers: {
  1173.                         'Content-Type': 'application/json',
  1174.  
  1175.                     },
  1176.                     body: JSON.stringify({
  1177.                         current_user_id: currentUserId,
  1178.                         replacement_user_id: replaceSelect,
  1179.                         project_id: projectId,
  1180.                         kt_link: ktLink
  1181.                     })
  1182.                 })
  1183.                     .then(response => response.json())
  1184.                     .then(data => {
  1185.                         if (data.status === 'success') {
  1186.                             console.log('Member replaced successfully');
  1187.                             window.location.reload();
  1188.                         } else {
  1189.                             console.error('Failed to replace member:', data.message);
  1190.                         }
  1191.                     })
  1192.                     .catch(error => console.error('Error:', error));
  1193.  
  1194.                 closeReplaceModal();
  1195.  
  1196.  
  1197.             }
  1198.  
  1199.  
  1200.             // fnction to open the Mark Absent modal
  1201.             function openMarkAbsentModal() {
  1202.  
  1203.                 event.preventDefault();
  1204.  
  1205.                 const row = document.getElementById(currentUserId);
  1206.                 if (!row) return; // Ensure the row exists
  1207.  
  1208.                 const teamMemberNameElement = row.querySelector('.team-member-name');
  1209.                 const name = teamMemberNameElement.childNodes[0].textContent.trim();
  1210.                 // populate the modal with the name
  1211.                 const nameElement = document.getElementById('mark-absent-name');
  1212.                 nameElement.textContent = ` Select a date to mark ${name} as absent.`;
  1213.  
  1214.                 // Show the modal
  1215.                 document.getElementById('mark-absent-modal').style.display = 'flex';
  1216.                 document.getElementById('overlay').style.display = 'block';
  1217.             }
  1218.  
  1219.             // function to mark a member as absent
  1220.             function markAbsent() {
  1221.                 if (event) {
  1222.                     event.preventDefault();
  1223.                 }
  1224.  
  1225.                 const row = document.getElementById(currentUserId);
  1226.                 if (!row) {
  1227.                     console.error('Row not found');
  1228.                     return;
  1229.                 }
  1230.  
  1231.                 const teamMemberNameElement = row.querySelector('.team-member-name');
  1232.                 const name = teamMemberNameElement.childNodes[0].textContent.trim();
  1233.                 const date = document.getElementById('absence-date').value;
  1234.                 fetch('/project/mark_absent/', {
  1235.                     method: 'POST',
  1236.                     headers: {
  1237.                         'Content-Type': 'application/json',
  1238.  
  1239.                     },
  1240.                     body: JSON.stringify({
  1241.                         user_id: currentUserId,
  1242.                         date: date
  1243.                     })
  1244.                 })
  1245.  
  1246.                     .then(response => response.json())
  1247.                     .then(data => {
  1248.                         if (data.status === "success") {
  1249.                             console.log(`${name} marked absent on ${date}`);
  1250.                             window.location.reload();
  1251.  
  1252.                         } else {
  1253.                             console.error('Failed to mark absent:', data.message);
  1254.                         }
  1255.                     })
  1256.                     .catch(error => console.error('Error:', error));
  1257.  
  1258.                 document.getElementById('absence-date').value = '';
  1259.  
  1260.                 closeMarkAbsentModal();
  1261.             }
  1262.  
  1263.             // function to close the Mark Absent modal
  1264.             function closeMarkAbsentModal() {
  1265.                 event.preventDefault();
  1266.                 document.getElementById('mark-absent-modal').style.display = 'none';
  1267.                 document.getElementById('overlay').style.display = 'none';
  1268.             }
  1269.  
  1270.             function openRemoveModal() {
  1271.  
  1272.                 const removeModal = document.getElementById('remove-modal');
  1273.  
  1274.                 // populate the modal with data from the selected row
  1275.                 const row = document.getElementById(currentUserId);
  1276.  
  1277.                 const teamMemberNameElement = row.querySelector('.team-member-name');
  1278.                 const name = teamMemberNameElement.childNodes[0].textContent.trim();
  1279.                 removeModal.style.display = 'block';
  1280.  
  1281.                 // pervent closing modal when clicking inside
  1282.                 removeModal.addEventListener('click', function (event) {
  1283.                     event.stopPropagation();
  1284.                 });
  1285.  
  1286.                 event.preventDefault();
  1287.             }
  1288.  
  1289.  
  1290.             function removeMember() {
  1291.                 event.preventDefault();
  1292.  
  1293.                 const row = document.getElementById(currentUserId);
  1294.                 if (!row) return;
  1295.  
  1296.                 const teamMemberNameElement = row.querySelector('.team-member-name');
  1297.                 const name = teamMemberNameElement.childNodes[0].textContent.trim();
  1298.                 const ktLink = document.getElementById('rev-kt-link').value;
  1299.  
  1300.                 const checkbox = document.getElementById('revoke-access-checkbox');
  1301.  
  1302.                 fetch('/project/removeMember/', {
  1303.                     method: 'POST',
  1304.  
  1305.                     headers: {
  1306.                         'Content-Type': 'application/json',
  1307.  
  1308.                     },
  1309.                     body: JSON.stringify({
  1310.                         user_id: currentUserId,
  1311.                         project_id: projectId,
  1312.                         revoke_repo: checkbox.checked,
  1313.                         kt_link: ktLink
  1314.                     })
  1315.                 })
  1316.                     .then(response => response.json())
  1317.                     .then(data => {
  1318.                         if (data.status === 'success') {
  1319.  
  1320.                             row.remove();
  1321.                             window.location.reload();
  1322.                         } else {
  1323.                        
  1324.                             console.error('Failed to remove team member:', data.message);
  1325.                         }
  1326.                     })
  1327.                     .catch(error => console.error('Error:', error));
  1328.  
  1329.                 closeRemoveModal();
  1330.  
  1331.             }
  1332.  
  1333.             function closeRemoveModal() {
  1334.                 event.preventDefault();
  1335.                 const removeModal = document.getElementById('remove-modal');
  1336.                 const overlay = document.getElementById('overlay');
  1337.  
  1338.                 removeModal.style.display = 'none';
  1339.                 // overlay.style.display = 'none';
  1340.             }
  1341.            
  1342.             function deleteDocument(element) {
  1343.                 // Get data from the clicked element
  1344.                 const documentName = element.dataset.documentName;
  1345.                 const documentUrl = element.dataset.documentUrl;
  1346.  
  1347.                 if (!projectId) {
  1348.                     console.error('Project ID not found');
  1349.                     return;
  1350.                 }
  1351.  
  1352.                 if (!confirm(`Are you sure you want to delete "${documentName}"?`)) {
  1353.                     return;
  1354.                 }
  1355.  
  1356.                 fetch('/project/delete-project-document/', {
  1357.                     method: 'POST',
  1358.                     headers: {
  1359.                         'Content-Type': 'application/json',
  1360.                         'X-CSRFToken': '{{ csrf_token }}',
  1361.                     },
  1362.                     body: JSON.stringify({
  1363.                         project_id: projectId,
  1364.                         document_name: documentName,
  1365.                         document_url: documentUrl
  1366.                     })
  1367.                 })
  1368.                 .then(response => response.json())
  1369.                 .then(data => {
  1370.                     if (data.status === 'success') {
  1371.                         // Remove the document from the UI
  1372.                         const docElement = element.closest('.mdoc-document-list-content');
  1373.                         if (docElement) {
  1374.                             docElement.remove();
  1375.                         }
  1376.                         // Show success message
  1377.                         alert('Document deleted successfully');
  1378.                     } else {
  1379.                         // Show error message
  1380.                         alert('Error deleting document: ' + data.message);
  1381.                     }
  1382.                 })
  1383.                 .catch(error => {
  1384.                     console.error('Error:', error);
  1385.                     alert('Error deleting document');
  1386.                 });
  1387.             }
  1388.  
  1389.             function editDocument(element) {
  1390.                 // Get data from the clicked element
  1391.                 const projectId = element.dataset.projectId;
  1392.                 const documentName = element.dataset.documentName;
  1393.                 const documentUrl = element.dataset.documentUrl;
  1394.                
  1395.                 // Store original values for later comparison
  1396.                 const modal = document.getElementById('editDocumentModal');
  1397.                 const form = document.getElementById('editDocumentForm');
  1398.                 const nameInput = document.getElementById('editDocumentName');
  1399.                 const urlInput = document.getElementById('editDocumentUrl');
  1400.  
  1401.                 // Set current values
  1402.                 nameInput.value = documentName;
  1403.                 urlInput.value = documentUrl;
  1404.                
  1405.                 // Store reference to the list item for updating UI later
  1406.                 const docElement = element.closest('.mdoc-document-list-content');
  1407.                
  1408.                 // Show modal
  1409.                 modal.style.display = 'block';
  1410.  
  1411.                 // Handle form submission
  1412.                 form.onsubmit = function(e) {
  1413.                     e.preventDefault();
  1414.                    
  1415.                     const newName = nameInput.value.trim();
  1416.                     const newUrl = urlInput.value.trim();
  1417.                    
  1418.                     // Don't make API call if nothing changed
  1419.                     if (newName === documentName && newUrl === documentUrl) {
  1420.                         closeEditModal();
  1421.                         return;
  1422.                     }
  1423.  
  1424.                     fetch('/project/edit-project-document/', {
  1425.                         method: 'POST',
  1426.                         headers: {
  1427.                             'Content-Type': 'application/json',
  1428.                             'X-CSRFToken': '{{ csrf_token }}',
  1429.                         },
  1430.                         body: JSON.stringify({
  1431.                             project_id: projectId,
  1432.                             old_name: documentName,
  1433.                             old_url: documentUrl,
  1434.                             new_name: newName,
  1435.                             new_url: newUrl
  1436.                         })
  1437.                     })
  1438.                     .then(response => response.json())
  1439.                     .then(data => {
  1440.                         if (data.status === 'success') {
  1441.                             // Update the UI
  1442.                             const nameElement = docElement.querySelector('.mdoc-document-list-name');
  1443.                             nameElement.textContent = newName;
  1444.                             nameElement.href = newUrl;
  1445.                            
  1446.                             // Update the data attributes
  1447.                             element.dataset.documentName = newName;
  1448.                             element.dataset.documentUrl = newUrl;
  1449.                            
  1450.                             closeEditModal();
  1451.                             alert('Document updated successfully');
  1452.                         } else {
  1453.                             alert('Error updating document: ' + data.message);
  1454.                         }
  1455.                     })
  1456.                     .catch(error => {
  1457.                         console.error('Error:', error);
  1458.                         alert('Error updating document');
  1459.                     });
  1460.                 };
  1461.             }
  1462.  
  1463.             function copyDocumentLink(element) {
  1464.                 let url = element.dataset.documentUrl;
  1465.    
  1466.                 // If the URL starts with /media, prepend the full domain
  1467.                 if (url.startsWith('/media')) {
  1468.                     // For development
  1469.                     if (window.location.hostname === 'localhost') {
  1470.                         url = `http://localhost:8000${url}`;
  1471.                     }
  1472.                     // For production
  1473.                     else {
  1474.                         url = `https://${window.location.host}${url}`;
  1475.                     }
  1476.                 }
  1477.  
  1478.                 // Create a temporary input element
  1479.                 const tempInput = document.createElement('input');
  1480.                 tempInput.value = url;
  1481.                 document.body.appendChild(tempInput);
  1482.                
  1483.                 // Select and copy the text
  1484.                 tempInput.select();
  1485.                 document.execCommand('copy');
  1486.                
  1487.                 // Remove the temporary element
  1488.                 document.body.removeChild(tempInput);
  1489.  
  1490.                 // Provide visual feedback
  1491.                 const originalText = element.textContent;
  1492.                 element.textContent = 'Copied!';
  1493.                 element.style.color = '#00B879'; // Green color for success
  1494.                
  1495.                 // Reset the button after 2 seconds
  1496.                 setTimeout(() => {
  1497.                     element.textContent = originalText;
  1498.                     element.style.color = ''; // Reset to default color
  1499.                 }, 2000);
  1500.             }
  1501.  
  1502.             function closeEditModal() {
  1503.                 const modal = document.getElementById('editDocumentModal');
  1504.                 modal.style.display = 'none';
  1505.                 document.getElementById('editDocumentForm').reset();
  1506.             }
  1507.  
  1508.             function togglePinDocument(element) {
  1509.                 const projectId = element.dataset.projectId;
  1510.                 const documentName = element.dataset.documentName;
  1511.                 const documentUrl = element.dataset.documentUrl;
  1512.                
  1513.                 fetch('/project/toggle-pin-document/', {
  1514.                     method: 'POST',
  1515.                     headers: {
  1516.                         'Content-Type': 'application/json',
  1517.                         'X-CSRFToken': '{{ csrf_token }}',
  1518.                     },
  1519.                     body: JSON.stringify({
  1520.                         project_id: projectId,
  1521.                         document_name: documentName,
  1522.                         document_url: documentUrl
  1523.                     })
  1524.                 })
  1525.                 .then(response => response.json())
  1526.                 .then(data => {
  1527.                     if (data.status === 'success') {
  1528.                         // Get the document container
  1529.                         const documentContainer = element.closest('.mdoc-document-list-content');
  1530.                        
  1531.                         // Update pinned status visually
  1532.                         documentContainer.setAttribute('data-pinned', data.pinned);
  1533.                         element.textContent = data.pinned ? 'Unpin Document' : 'Pin Document';
  1534.                        
  1535.                         // Refresh document list to maintain order
  1536.                         const documentList = document.getElementById('document-list');
  1537.                         const documents = Array.from(documentList.children);
  1538.                        
  1539.                         // Sort documents (pinned first)
  1540.                         documents.sort((a, b) => {
  1541.                             const aPinned = a.getAttribute('data-pinned') === 'true';
  1542.                             const bPinned = b.getAttribute('data-pinned') === 'true';
  1543.                             return bPinned - aPinned;
  1544.                         });
  1545.                        
  1546.                         // Clear and re-append sorted documents
  1547.                         documentList.innerHTML = '';
  1548.                         documents.forEach(doc => documentList.appendChild(doc));
  1549.                        
  1550.                     } else {
  1551.                         alert('Error updating pin status: ' + data.message);
  1552.                     }
  1553.                 })
  1554.                 .catch(error => {
  1555.                     console.error('Error:', error);
  1556.                     alert('Error updating pin status');
  1557.                 });
  1558.             }
  1559.  
  1560.             /* PROJECT DETAIL CHANGES */
  1561.             let milestonesDict = {}; // This will store milestone details
  1562.  
  1563.             function showMilestoneDetailPopup(event,milestoneId) {
  1564.                 const milestoneElement = document.getElementById(milestoneId);
  1565.                 const popup = document.getElementById("milestone-popup");
  1566.                 popup.dataset.milestoneId = milestoneId;
  1567.                 const clickedDiv = event.currentTarget;
  1568.                 const rect = clickedDiv.getBoundingClientRect();
  1569.                 const offsetX = window.scrollX;
  1570.                 const offsetY = window.scrollY;
  1571.  
  1572.  
  1573.                 popup.style.left = `${(rect.left + offsetX)/zoom}px`;
  1574.                 popup.style.top = `${(rect.bottom + offsetY)/zoom}px`;
  1575.                 popup.style.display = 'flex';
  1576.                
  1577.                 const handleClickOutside = (event) => {
  1578.                     if (!popup.contains(event.target) && !clickedDiv.contains(event.target)) {
  1579.                         closeMilestoneDetailPopup();
  1580.                         document.removeEventListener('click', handleClickOutside);
  1581.                     }
  1582.                 };
  1583.  
  1584.                 document.addEventListener('click', handleClickOutside);
  1585.                
  1586.            
  1587.                 // Populate start and end dates from existing data if available
  1588.                 const milestone = milestoneStatuses[milestoneId] || {};
  1589.                 document.getElementById("rename-milestone").value = milestoneId ;
  1590.                 document.getElementById("milestone-start-date").value = formatDateForInput(milestone.start) ;
  1591.                 document.getElementById("milestone-end-date").value = formatDateForInput(milestone.end);
  1592.                 document.getElementById("milestone-budget").value = milestone.budget || 0;
  1593.                 const milestoneTypeLabel = document.querySelector('.milestone-type .milestone-type-block');
  1594.                 if (milestone.type) {
  1595.                     // Map the backend value to display text
  1596.                     const typeMap = {
  1597.                         'retainer': 'Retainer Based',
  1598.                         'fixed': 'Fixed Cost'
  1599.                     };
  1600.                     milestoneTypeLabel.innerHTML = typeMap[milestone.type] || '';
  1601.                     // Store the actual value as a data attribute
  1602.                     milestoneTypeLabel.dataset.value = milestone.type;
  1603.                 }
  1604.             }
  1605.  
  1606.             function closeMilestoneDetailPopup() {
  1607.                 const milestoneId = document.getElementById('milestone-popup').getAttribute('data-milestone-id');
  1608.                
  1609.                 // Get the start and end date values from the popup inputs
  1610.                 const milestoneName = document.getElementById("rename-milestone").value;
  1611.                 const startDateValue = document.getElementById("milestone-start-date").value;
  1612.                 const endDateValue = document.getElementById("milestone-end-date").value;
  1613.                 const milestoneBudgetValue = document.getElementById("milestone-budget").value;
  1614.                 const typeLabel = document.querySelector('.milestone-type .milestone-type-block');
  1615.                 const milestoneTypeValue = typeLabel.dataset.value || 'retailer';
  1616.  
  1617.                 // Only update the current milestone instead of replacing everything
  1618.                 if (milestoneId && milestoneStatuses[milestoneId]) {
  1619.                     // Format the dates as required by Django
  1620.                     const formattedStartDate = startDateValue ? formatDateForInput(startDateValue) : milestoneStatuses[milestoneId].start;
  1621.                     const formattedEndDate = endDateValue ? formatDateForInput(endDateValue) : milestoneStatuses[milestoneId].end;
  1622.                    
  1623.                     // Prepare the updated milestone data
  1624.                     milestoneStatuses[milestoneId] = {
  1625.                         ...milestoneStatuses[milestoneId], // Preserve existing properties like ID
  1626.                         start: formattedStartDate,
  1627.                         end: formattedEndDate,
  1628.                         budget: milestoneBudgetValue || milestoneStatuses[milestoneId].budget,
  1629.                         type: milestoneTypeValue,
  1630.                     };
  1631.                    
  1632.                     // Check if a new milestone name is provided and is different from the current ID
  1633.                     if (milestoneName && milestoneName !== milestoneId) {
  1634.                         // Remove the old entry and create a new one with the updated name
  1635.                         const oldMilestoneData = {...milestoneStatuses[milestoneId]};
  1636.                         delete milestoneStatuses[milestoneId];
  1637.                         milestoneStatuses[milestoneName] = oldMilestoneData;
  1638.                        
  1639.                         // Update the data-milestone-id attribute with the new name
  1640.                         document.getElementById('milestone-popup').setAttribute('data-milestone-id', milestoneName);
  1641.                         const milestoneElements = document.getElementsByName('edit-' + milestoneId);
  1642.                         const milestoneElement = milestoneElements.length > 0 ? milestoneElements[0] : null;
  1643.                         if (milestoneElement) {
  1644.                             milestoneElement.setAttribute('name', 'edit-' + milestoneName);
  1645.                             milestoneElement.setAttribute('id', milestoneName);
  1646.                             milestoneElement.children[0].textContent = milestoneName;
  1647.                         }
  1648.                     }
  1649.                 }
  1650.                
  1651.                 // Hide the popup
  1652.                 document.getElementById('milestone-popup').style.display = 'none';
  1653.             }
  1654.            
  1655.             function endMilestone() {
  1656.                 event.preventDefault();
  1657.                 const milestoneId = document.getElementById("milestone-popup").dataset.milestoneId;
  1658.                 milestoneStatuses[milestoneId].status = "completed";
  1659.                
  1660.                
  1661.                 const milestoneElements = document.getElementsByName('edit-' + milestoneId);
  1662.                 const milestoneElement = milestoneElements.length > 0 ? milestoneElements[0] : null;
  1663.  
  1664.                 if (milestoneElement) {
  1665.                     // Proceed with updating milestone color
  1666.                     updateMilestoneColor(milestoneElement, "completed");
  1667.                 } else {
  1668.                     console.log("No element found with the specified name.");
  1669.                 }
  1670.  
  1671.                
  1672.                 closeMilestoneDetailPopup();
  1673.             }
  1674.  
  1675.             function addMilestone(event, element, type) {
  1676.                 event.preventDefault();
  1677.                 // Increment the milestone count for the new milestone
  1678.                 milestoneCount++;
  1679.                 milestoneStatuses["M"+milestoneCount]={"id":"0","status":"incomplete","start":"","end":"","budget":0.0,"type":"retainer"}
  1680.  
  1681.                 let span = document.createElement('span');
  1682.                 span.className='display-milestone';
  1683.                 span.id=`M${milestoneCount}`
  1684.                 span.setAttribute('name', `edit-${span.id}`);
  1685.                 span.innerHTML=`
  1686.                     <p>M${milestoneCount}</p>
  1687.                     <svg width="10" height="6" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  1688.                         <path d="M1 1L7 7L13 1" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
  1689.                         </svg>
  1690.                         `
  1691.                         // Insert the new milestone input after the current element
  1692.                         element.parentElement.insertAdjacentElement('beforebegin', span);
  1693.                         span.addEventListener('click', (e)=>{
  1694.                             showMilestoneDetailPopup(e, span.id);
  1695.                         })
  1696.             }
  1697.  
  1698.             function removeMilestone(element) {
  1699.                 event.preventDefault();
  1700.                 // Remove the milestone input div
  1701.                 element.parentElement.remove();
  1702.                 milestoneCount--;
  1703.             }
  1704.             function addInputTextField(element, name) {
  1705.                 event.preventDefault();
  1706.                 const div = document.createElement('div');
  1707.                 div.className = 'client-input-row';
  1708.                 div.style.position="relative"
  1709.                 div.innerHTML = `
  1710.                         <input class="input-style client-name-input" type="text" id= "${name}" name="${name}" placeholder="Add a ${name.replace('-', ' ')}">
  1711.                         <span class="delete-icon" onclick="removeInputField(this)">&#10006;</span>
  1712.                 `;
  1713.                 // element.insertAdjacentElement('beforebegin', div);
  1714.                 element.parentElement.insertAdjacentElement('afterend', div);
  1715.             }
  1716.             let currentTaskId = ""
  1717.             // Track event listeners in an object or array
  1718.             let eventListeners = [];
  1719.  
  1720.         async function openTaskModal(taskId) {
  1721.             let taskData = {};
  1722.  
  1723.             try {
  1724.                 // Make the API call to get task data
  1725.                 const response = await fetch(`/project/get/tasks/${taskId}`);
  1726.                 if (!response.ok) {
  1727.                     throw new Error('Failed to fetch task data');
  1728.                 }
  1729.  
  1730.                 // Parse the JSON response
  1731.                 taskData = await response.json();
  1732.                 currentTaskId = taskId;
  1733.                 populateData(taskData);
  1734.  
  1735.                 // 1. Description Field Event Listener with Timeout (for saving after delay)
  1736.                 const descriptionField = document.getElementById('task-description');
  1737.                 let timeoutId; // To hold the timeout reference
  1738.                 const descriptionListener = function () {
  1739.                     clearTimeout(timeoutId);
  1740.                     timeoutId = setTimeout(async function () {
  1741.                         // Make API call to save the updated description
  1742.                         await saveDescription(taskId, descriptionField.value);
  1743.                     }, 1000); // Delay the API call by 1 second after typing stops
  1744.                 };
  1745.                 descriptionField.addEventListener('change', descriptionListener);
  1746.                 eventListeners.push({ element: descriptionField, type: 'change', listener: descriptionListener });
  1747.  
  1748.                 const enterListener = async function (event) {
  1749.                     if (event.key === 'Enter') {
  1750.                         // Save the description when Enter key is pressed
  1751.                         await saveDescription(taskId, descriptionField.value);
  1752.                     }
  1753.                 };
  1754.                
  1755.                 // Listen for keydown event to capture Enter key press
  1756.                 descriptionField.addEventListener('keydown', enterListener);
  1757.                 eventListeners.push({ element: descriptionField, type: 'keydown', listener: enterListener });
  1758.  
  1759.                 // 2. Type Button Toggle (Task / Checkpoint)
  1760.                 const typeButton = document.getElementById('task-type');
  1761.                 const typeButtonListener = function () {
  1762.                     const newType = taskData.type == "Checkpoint"  ? 'Task' : 'Checkpoint';
  1763.                     taskData.type = newType;
  1764.                     typeButton.textContent = newType;
  1765.                     if (newType == "Checkpoint"){
  1766.                         typeButton.style.background = "orange";
  1767.                     }
  1768.                     else{
  1769.                         typeButton.style.background = "#504CF5";
  1770.                     }
  1771.                     // Optionally, update backend with the new type
  1772.                     saveTaskType(taskId, newType);
  1773.                 };
  1774.                 typeButton.addEventListener('click', typeButtonListener);
  1775.                 eventListeners.push({ element: typeButton, type: 'click', listener: typeButtonListener });
  1776.  
  1777.                 // 3. Name Field Toggle to Input
  1778.                 const nameField = document.getElementById('task-title');
  1779.                 const nameFieldListener = function () {
  1780.                     const inputField = document.createElement('input');
  1781.                     inputField.value = nameField.textContent; // Set the current name as value
  1782.                     inputField.className = 'name-input';
  1783.                     inputField.addEventListener('blur', async function () {
  1784.                         // Save the updated name on blur (focus out)
  1785.                         await saveTaskName(taskId, inputField.value);
  1786.                         nameField.textContent = inputField.value; // Set name to the new value
  1787.                         nameField.style.display = 'block';
  1788.                         inputField.remove(); // Remove the input field
  1789.                     });
  1790.                     inputField.addEventListener('keydown', async function (event) {
  1791.                         if (event.key === 'Enter') {
  1792.                             // Save the updated name when Enter is pressed
  1793.                             await saveTaskName(taskId, inputField.value);
  1794.                             nameField.textContent = inputField.value; // Set name to the new value
  1795.                             nameField.style.display = 'block'; // Show the name field again
  1796.                             inputField.remove(); // Remove the input field
  1797.                         }
  1798.                     });
  1799.                
  1800.  
  1801.                     nameField.style.display = 'none'; // Hide the original name
  1802.                     nameField.parentElement.appendChild(inputField); // Append the input field
  1803.                     inputField.focus(); // Focus the input field immediately
  1804.                 };
  1805.  
  1806.                
  1807.                 nameField.addEventListener('click', nameFieldListener);
  1808.                 eventListeners.push({ element: nameField, type: 'click', listener: nameFieldListener });
  1809.  
  1810.             } catch (error) {
  1811.                 console.error('Error fetching task data:', error);
  1812.                 alert('Unable to load task details. Please try again later.');
  1813.             }
  1814.         }
  1815.  
  1816.         // Function to remove event listeners
  1817.         function closeTaskModal() {
  1818.             const modalOverlay = document.getElementById('task-modal');
  1819.             modalOverlay.style.display = 'none'; // Hide the modal
  1820.  
  1821.             // Remove all event listeners that were added
  1822.             eventListeners.forEach(item => {
  1823.                 item.element.removeEventListener(item.type, item.listener);
  1824.             });
  1825.  
  1826.             // Clear the event listeners array
  1827.             eventListeners = [];
  1828.         }
  1829.  
  1830.         // Function to save the description (on change after timeout)
  1831.         async function saveDescription(taskId, description) {
  1832.             try {
  1833.                 const response = await fetch(`/project/update-description/${taskId}/`, {
  1834.                     method: 'POST',
  1835.                     headers: {
  1836.                         'Content-Type': 'application/json',
  1837.                     },
  1838.                     body: JSON.stringify({ description: description }),
  1839.                 });
  1840.                 if (response.ok) {
  1841.                     console.log('Description saved');
  1842.                 } else {
  1843.                     console.error('Failed to save description');
  1844.                 }
  1845.             } catch (error) {
  1846.                 console.error('Error saving description:', error);
  1847.             }
  1848.         }
  1849.  
  1850.         // Function to save the task type (on button click toggle)
  1851.         async function saveTaskType(taskId, type) {
  1852.             try {
  1853.                 const response = await fetch(`/project/update-type/${taskId}/`, {
  1854.                     method: 'POST',
  1855.                     headers: {
  1856.                         'Content-Type': 'application/json',
  1857.                     },
  1858.                     body: JSON.stringify({ type: type }),
  1859.                 });
  1860.                 if (response.ok) {
  1861.                     console.log('Task type saved');
  1862.                    
  1863.                 } else {
  1864.                     console.error('Failed to save task type');
  1865.                 }
  1866.             } catch (error) {
  1867.                 console.error('Error saving task type:', error);
  1868.             }
  1869.         }
  1870.  
  1871.         // Function to save the task name (on blur)
  1872.         async function saveTaskName(taskId, name) {
  1873.             try {
  1874.                 const response = await fetch(`/project/rename/${taskId}/`, {
  1875.                     method: 'POST',
  1876.                     headers: {
  1877.                         'Content-Type': 'application/json',
  1878.                     },
  1879.                     body: JSON.stringify({ name: name }),
  1880.                 });
  1881.                 if (response.ok) {
  1882.                     console.log('Task name saved');
  1883.                 } else {
  1884.                     console.error('Failed to save task name');
  1885.                 }
  1886.             } catch (error) {
  1887.                 console.error('Error saving task name:', error);
  1888.             }
  1889.         }
  1890.  
  1891.            
  1892.             function populateData(taskData){
  1893.  
  1894.            
  1895.                 const modalOverlay = document.getElementById('task-modal');
  1896.                 const taskModal = modalOverlay.querySelector('.task-modal');
  1897.                 const assignIcon = document.getElementById('task-assignee')
  1898.                 assignee = "No assignee";
  1899.                 if (taskData.assignee){
  1900.                     assignIcon.innerText = taskData.assignee;
  1901.                    
  1902.                 }
  1903.                 else{
  1904.                     assignIcon.innerText = assignee;
  1905.                 }
  1906.                
  1907.                
  1908.                 // Populate the task data in the modal
  1909.                 document.getElementById('task-project').innerText = taskData.project;
  1910.                 document.getElementById('task-project').style.paddingRight = "5px";
  1911.                 document.getElementById('task-milestone').style.paddingLeft = "5px";
  1912.                 document.getElementById('task-milestone').innerText = taskData.milestone;
  1913.                 const typeButton = document.getElementById('task-type')
  1914.                 typeButton.innerText = taskData.type;
  1915.  
  1916.                 if (taskData.type== "Checkpoint"){
  1917.                     typeButton.style.background = "orange";
  1918.                 }
  1919.                 else{
  1920.                     typeButton.style.background = "#504CF5";
  1921.                 }
  1922.                 document.getElementById('task-title').innerText = taskData.title;
  1923.                 document.getElementById('task-status').innerText = taskData.status;
  1924.                 document.getElementById('task-start-date').innerText = taskData.start_date;
  1925.                 document.getElementById('task-due-date').innerText = taskData.due_date || "No Due Date";
  1926.                
  1927.                 document.getElementById('task-description').value = taskData.description;
  1928.            
  1929.                 // Dynamically populate links
  1930.                 if (taskData.links){
  1931.                     populateLinks(taskData.links);
  1932.                 }
  1933.                
  1934.            
  1935.                 if (taskData.prs){
  1936.                     populatePRs(taskData.prs);
  1937.                 }
  1938.                
  1939.  
  1940.                 if (taskData.activity) {
  1941.                     populateActivitySection(taskData.activity);
  1942.                 }
  1943.                 else{
  1944.                     const activitiesList = document.getElementById('activities-list');
  1945.                     activitiesList.innerHTML = '';
  1946.                     const activityItem = document.createElement('div');
  1947.                     activityItem.classList.add('activity-item');
  1948.                     activityItem.innerHTML = "No activity yet."
  1949.                     activitiesList.appendChild(activityItem);
  1950.                 }
  1951.            
  1952.                 // Show the modal overlay (making it visible)
  1953.                 modalOverlay.style.display = 'block';
  1954.             }
  1955.             // Function to close the modal
  1956.            
  1957.            
  1958.         // Function to dynamically populate Links as a styled list with name and URL
  1959.         function populateLinks(links) {
  1960.             const linksContainer = document.getElementById('links-container');
  1961.             linksContainer.innerHTML = ''; // Clear existing links
  1962.  
  1963.             const ul = document.createElement('ul'); // Create an unordered list for links
  1964.             ul.id = "links-ul";
  1965.             ul.classList.add('link-list'); // Adding class for styling
  1966.  
  1967.             links.forEach(link => {
  1968.                 const li = document.createElement('li');
  1969.                 li.classList.add('link-item'); // Applying item style
  1970.  
  1971.                 // Assuming each link object has a 'name' and 'url' property
  1972.                 li.innerHTML = `
  1973.                      <div class="link-item-container">
  1974.                         <a href="${link.url}" target="_blank" class="link-text">${link.name}</a>
  1975.                         <button title="Delete Link" onclick="deleteItem(this, 'link', '${link.url}')" class="remove-btn">
  1976.                             <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  1977.                                 <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  1978.                             </svg>
  1979.                         </button>
  1980.                     </div>
  1981.                 `;
  1982.  
  1983.                 ul.appendChild(li);
  1984.             });
  1985.  
  1986.             linksContainer.appendChild(ul);
  1987.         }
  1988.         function populateActivitySection(activityData) {
  1989.             const activitiesList = document.getElementById('activities-list');
  1990.             activitiesList.innerHTML = ''; // Clear previous activities
  1991.        
  1992.             activityData.forEach(activity => {
  1993.                 const activityItem = document.createElement('div');
  1994.                 activityItem.classList.add('activity-item');
  1995.        
  1996.                 // Create content and timestamp elements
  1997.                 const contentElement = document.createElement('div');
  1998.                 contentElement.classList.add('activity-content');
  1999.                 contentElement.textContent = activity.content;
  2000.        
  2001.                 const timestampElement = document.createElement('div');
  2002.                 timestampElement.classList.add('activity-timestamp');
  2003.                 timestampElement.textContent = activity.timestamp;
  2004.                 timestampElement.style.color = "#ccc";
  2005.                 timestampElement.title = "Timestamp";
  2006.        
  2007.                 // Append content and timestamp to the activity item
  2008.                 activityItem.appendChild(contentElement);
  2009.                 activityItem.appendChild(timestampElement);
  2010.        
  2011.                 // Append activity item to the activities list
  2012.                 activitiesList.appendChild(activityItem);
  2013.             });
  2014.         }
  2015.         // Function to dynamically populate PRs as a styled list
  2016.         function populatePRs(prs) {
  2017.             const prsContainer = document.getElementById('prs-container');
  2018.             prsContainer.innerHTML = ''; // Clear existing PRs
  2019.        
  2020.             const ul = document.createElement('ul'); // Create an unordered list for PRs
  2021.             ul.id = "prs-ul";
  2022.             ul.classList.add('pr-list'); // Adding class for styling
  2023.        
  2024.             prs.forEach(pr => {
  2025.                 const li = document.createElement('li');
  2026.                 li.classList.add('link-item'); // Applying item style
  2027.                 li.classList.add('pr-hover'); // Adding hover class to show delete button
  2028.                 let color = "red"
  2029.                 if (pr.state == "closed"){
  2030.                     color = "green";
  2031.                 }
  2032.                 li.innerHTML = `
  2033.                 <div class="pr-item-container link-item-container">
  2034.                     <a href="${pr.url}" target="_blank" class="pr-text">${pr.name}
  2035.                       <span id="pr-state" style="color:${color}"> (${pr.state}) </span>
  2036.                     </a>
  2037.                     <button title="Delete PR" onclick="deleteItem(this, 'pr', '${pr.url}')" class="remove-btn">
  2038.                         <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  2039.                             <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  2040.                         </svg>
  2041.                     </button>
  2042.                 </div>
  2043.                 `;
  2044.                 li.title = pr.state;
  2045.                
  2046.                 ul.appendChild(li);
  2047.             });
  2048.        
  2049.             prsContainer.appendChild(ul);
  2050.             prsContainer.appendChild(ul);
  2051.         }
  2052.        
  2053.         function deleteItem(button, type, url) {
  2054.             const item = button.closest('.link-item'); // Find the parent item (PR or link)
  2055.        
  2056.             // Send the DELETE request to the backend
  2057.             fetch(`/project/task/delete_item/`, {
  2058.                 method: 'DELETE',
  2059.                 headers: {
  2060.                     'Content-Type': 'application/json',
  2061.                 },
  2062.                 body: JSON.stringify({ type: type, url: url,task_id: currentTaskId }) // Send both type and url to backend
  2063.             })
  2064.             .then(response => response.json())
  2065.             .then(data => {
  2066.                 if (data.status === 'success') {
  2067.                    
  2068.                     item.remove();
  2069.                 } else {
  2070.                     alert("Error deleting item.");
  2071.                 }
  2072.             })
  2073.             .catch(error => {
  2074.                 console.error("Error:", error);
  2075.                 alert("There was an issue deleting the item.");
  2076.             });
  2077.         }
  2078.        
  2079.  
  2080.  
  2081.         function addTaskInputField(type) {
  2082.             const container = document.getElementById(type + '-container');
  2083.             const inputGroup = document.createElement('div');
  2084.             inputGroup.classList.add('input-group');
  2085.          
  2086.             inputGroup.innerHTML = `
  2087.                 <div class="input-fields-container">
  2088.                     <input class="dynamic-input" type="text" placeholder="Enter ${type === 'links' ? 'link' : 'PR'} name">
  2089.                     <input class="dynamic-input" type="text" placeholder="Enter ${type === 'links' ? 'link' : 'PR'} URL">
  2090.                 </div>
  2091.                 <div class="button-container">
  2092.                     <button class="add-button save-button" onclick="saveLink(this, '${type}')">Save</button>
  2093.                     <button class="remove-button" onclick="removeTaskInputField(this)">Remove</button>
  2094.                 </div>
  2095.             `;
  2096.          
  2097.             container.appendChild(inputGroup);
  2098.         }
  2099.          
  2100.               function removeTaskInputField(button) {
  2101.  
  2102.                 button.parentElement.parentElement.remove();
  2103.                
  2104.               }
  2105.          
  2106.               function saveLink(button, type) {
  2107.                 const inputFields = button.parentElement.previousElementSibling.querySelectorAll('input');
  2108.                 const name = inputFields[0].value;
  2109.                 const url = inputFields[1].value;
  2110.          
  2111.                 if (name && url) {
  2112.                     const data = {
  2113.                         name: name,
  2114.                         url: url
  2115.                     };
  2116.            
  2117.                     // Send the data to the backend API
  2118.                     fetch('/project/task/save_link/', {
  2119.                         method: 'POST',
  2120.                         headers: {
  2121.                             'Content-Type': 'application/json',
  2122.                         },
  2123.                         body: JSON.stringify({
  2124.                             type: type,  
  2125.                             data: data,
  2126.                             task_id : currentTaskId
  2127.                         })
  2128.                     })
  2129.                     .then(response => response.json())
  2130.                     .then(data => {
  2131.                         ul = document.getElementById(`${type}-ul`);
  2132.                         const li = document.createElement('li');
  2133.                         li.classList.add('link-item'); // Applying item style
  2134.  
  2135.                         // Assuming each link object has a 'name' and 'url' property
  2136.                         li.innerHTML = `
  2137.                             <div class="link-item-container">
  2138.                                 <a href="${url}" target="_blank" class="pr-text">${name}</a>
  2139.                                 <button title="Delete PR" onclick="deleteItem(this, '${type}', '${url}')" class="remove-btn">
  2140.                                     <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  2141.                                         <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  2142.                                     </svg>
  2143.                                 </button>
  2144.                             </div>
  2145.                         `;
  2146.  
  2147.                         ul.appendChild(li);
  2148.                         button.parentElement.parentElement.remove(); // Remove the input group after saving
  2149.                     })
  2150.                     .catch(error => {
  2151.                         alert("There was an error saving the link.");
  2152.                         console.error('Error:', error);
  2153.                     });
  2154.                 } else {
  2155.                     alert("Please enter both name and URL.");
  2156.                 }
  2157.             }
  2158.  
  2159.             function addInputField(element, name) {
  2160.                 event.preventDefault();
  2161.                 const div = document.createElement('div');
  2162.                 div.className = 'project-details-input';
  2163.                 div.innerHTML = `
  2164.                     <label  for="${name}"></label>
  2165.                     <div>
  2166.                         <input class="input-style" type="text" id= "${name}" name="${name}" placeholder="Add a ${name.replace('-', ' ')}">
  2167.                         <span class="delete-icon" onclick="removeInputField(this)">&#10006;</span>
  2168.                     </div>
  2169.                 `;
  2170.                 element.parentElement.parentElement.parentElement.insertAdjacentElement('afterend', div);
  2171.             }
  2172.  
  2173.             function removeInputField(element) {
  2174.                 element.parentElement.remove();
  2175.             }
  2176.  
  2177.             function removeInputTextField(element) {
  2178.                 element.parentElement.parentElement.remove();
  2179.             }
  2180.        
  2181.            
  2182.             function openModal() {
  2183.                 document.getElementById('modal').style.display = 'flex';
  2184.             }
  2185.  
  2186.            
  2187.             function closeModal() {
  2188.                 document.getElementById('modal').style.display = 'none';
  2189.             }
  2190.  
  2191.  
  2192.             /* GIT FUNCTIONALITY */
  2193.             let typingTimer;                // Timer identifier
  2194.             const typingDelay = 1000;       // Time in ms (1 second)
  2195.             const repoNameInput = document.getElementById('repo-name');
  2196.             const statusElement = document.getElementById('repo-status');
  2197.  
  2198.             // Function to check repository name availability
  2199.             async function checkRepoAvailability(repoName, owner, org) {
  2200.                 try {
  2201.                     const response = await fetch('/project/check-repo-exists/', {
  2202.                         method: 'POST',
  2203.                         headers: {
  2204.                             'Content-Type': 'application/json',
  2205.                         },
  2206.                         body: JSON.stringify({
  2207.                             name: repoName,
  2208.                             owner: owner,
  2209.                             org: org // Include the org if it is provided
  2210.                         }),
  2211.                     });
  2212.            
  2213.                     const data = await response.json();
  2214.                     if (response.ok) {
  2215.                         return data.exists; // Returns true or false
  2216.                     } else {
  2217.                         throw new Error(data.error || 'Unknown error while checking repository');
  2218.                     }
  2219.                 } catch (error) {
  2220.                     console.error('Error checking repository:', error.message);
  2221.                     return null; // Error occurred
  2222.                 }
  2223.             }
  2224.            
  2225.  
  2226.             // Function to handle typing event
  2227.             async function handleTyping() {
  2228.                 const repoName = repoNameInput.value.trim();
  2229.                 const owner = document.getElementById('owner').value;
  2230.  
  2231.                 if (repoName) {
  2232.                     const exists = await checkRepoAvailability(repoName, owner);
  2233.  
  2234.                     if (exists === null) {
  2235.                         statusElement.textContent = 'Error checking repository availability. Please try again.';
  2236.                         statusElement.style.color = 'red';
  2237.                     } else if (exists) {
  2238.                         statusElement.textContent = `${repoName} is already taken.`;
  2239.                         statusElement.style.color = 'red';
  2240.                     } else {
  2241.                         statusElement.textContent = `${repoName} is available.`;
  2242.                         statusElement.style.color = 'green';
  2243.                     }
  2244.                 } else {
  2245.                     statusElement.textContent = 'Please enter a repository name.';
  2246.                     statusElement.style.color = 'red';
  2247.                 }
  2248.             }
  2249.  
  2250.             // Event listener for typing
  2251.             repoNameInput.addEventListener('keyup', () => {
  2252.                 clearTimeout(typingTimer); // Clear the timer if the user is still typing
  2253.                 typingTimer = setTimeout(handleTyping, typingDelay); // Set a new timer
  2254.             });
  2255.  
  2256.             // Optional: Clear the status if the user starts typing again
  2257.             repoNameInput.addEventListener('keydown', () => {
  2258.                 clearTimeout(typingTimer); // Clear the timer to prevent premature checks
  2259.                 statusElement.textContent = ''; // Clear the status text
  2260.             });
  2261.  
  2262.             async function createRepo(repoName, owner, org) {
  2263.                 try {
  2264.                     const response = await fetch('/project/create-repo/', {
  2265.                         method: 'POST',
  2266.                         headers: {
  2267.                             'Content-Type': 'application/json',
  2268.                         },
  2269.                         body: JSON.stringify({
  2270.                             name: repoName,
  2271.                             owner: owner,
  2272.                             org: org, // Include org if it's an organization
  2273.                             project_id: "{{project_detail.id}}"
  2274.                         }),
  2275.                     });
  2276.            
  2277.                     const data = await response.json();
  2278.                     if (response.ok) {
  2279.                         return { success: true, message: data.message };
  2280.                     } else {
  2281.                         throw new Error(data.error || 'Unknown error while creating repository');
  2282.                     }
  2283.                 } catch (error) {
  2284.                     console.error('Error creating repository:', error);
  2285.                     return { success: false, message: error};
  2286.                 }
  2287.             }
  2288.             // Function to handle repository creation process
  2289.                 async function createRepository() {
  2290.                     const repoName = document.getElementById('repo-name').value.trim();
  2291.                     const owner = document.getElementById('owner').value; // Can be a user or an org
  2292.                     const org = document.getElementById('organization').value; // Optional org selection
  2293.                     const statusElement = document.getElementById('repo-status');
  2294.  
  2295.                     // Validate inputs
  2296.                     if (!repoName || !owner) {
  2297.                         statusElement.textContent = 'Please provide both owner and repository name.';
  2298.                         statusElement.style.color = 'red';
  2299.                         return;
  2300.                     }
  2301.  
  2302.                     // Check if the repository already exists based on whether it's an org or user
  2303.                     const exists = await checkRepoAvailability(repoName, owner, org);
  2304.  
  2305.                     // Handle errors from the availability check
  2306.                     if (exists === null) {
  2307.                         statusElement.textContent = 'Error checking repository availability. Please try again.';
  2308.                         statusElement.style.color = 'red';
  2309.                         return;
  2310.                     }
  2311.  
  2312.                     // Inform the user if the repository already exists
  2313.                     if (exists) {
  2314.                         statusElement.textContent = `${repoName} already exists.`;
  2315.                         statusElement.style.color = 'red';
  2316.                     } else {
  2317.                         // Attempt to create the repository
  2318.                         const result = await createRepo(repoName, owner, org);
  2319.                         if (result.success) {
  2320.                             // Show success message and reload the page
  2321.                             statusElement.textContent = result.message;
  2322.                             statusElement.style.color = 'green';
  2323.                             window.location.reload();
  2324.                         } else {
  2325.                             // Show error message if creation failed
  2326.                             statusElement.textContent = result.message;
  2327.                             statusElement.style.color = 'red';
  2328.                         }
  2329.                     }
  2330.                 }
  2331.            
  2332.            
  2333.                 function toggleCreateRepoForm() {
  2334.                     const repoForm = document.getElementById("repo-form");
  2335.                     const existingRepositories = document.getElementById("modal-content-exisiting-repo");
  2336.                
  2337.                     // Toggle visibility
  2338.                     if (repoForm.style.display === "none") {
  2339.                         repoForm.style.display = "flex";
  2340.                         existingRepositories.style.display = "none"; // Hide existing repositories
  2341.                     } else {
  2342.                         repoForm.style.display = "none";
  2343.                         existingRepositories.style.display = "flex"; // Show existing repositories
  2344.                     }
  2345.                 }
  2346.                
  2347.                 function openAssignRepoModal() {
  2348.                     document.getElementById("assignRepoModal").style.display = "block";
  2349.                     const currentUserIdAsNumber = Number(currentUserId); // Convert the global variable to a number
  2350.                    
  2351.                
  2352.                     const member = members.find(member => member.id === currentUserIdAsNumber);
  2353.                    
  2354.                     if (member) {
  2355.                         var name = member.username;
  2356.                        
  2357.                        
  2358.                         if (member.name && member.name!== " ") {
  2359.                             name = member.name;
  2360.                         } else {
  2361.                             name = member.username;
  2362.                         }
  2363.    
  2364.                         document.getElementById("assign-modal-title").innerText = "Assign GitHub Repo to " + name;
  2365.                         if (!member.github_username) {
  2366.                             // Display the warning message and disable the form
  2367.                             document.getElementById("github-warning").innerHTML =  
  2368.                             name + " has not set their GitHub username. </br> Please ask them to set their github username before assigning repositories.";
  2369.                             document.getElementById("github-warning").style.display = "block";
  2370.                            
  2371.                             // Disable checkboxes and submit button
  2372.                             disableForm(true);
  2373.                         } else {
  2374.                             // Hide the warning message and enable the form
  2375.                             document.getElementById("github-warning").style.display = "none";
  2376.                             disableForm(false);
  2377.                         }
  2378.                     } else {
  2379.                         console.error("Member not found.");
  2380.                     }
  2381.                 }
  2382.                
  2383.                 function openRevokeRepoModal() {
  2384.                     document.getElementById("revokeRepoModal").style.display = "flex";
  2385.                     const currentUserIdAsNumber = Number(currentUserId);
  2386.                    
  2387.                
  2388.                     const member = members.find(member => member.id === currentUserIdAsNumber);
  2389.                    
  2390.                     if (member) {
  2391.                         var name = member.username;
  2392.                        
  2393.                        
  2394.                         if (member.name && member.name!== " ") {
  2395.                             name = member.name;
  2396.                         } else {
  2397.                             name = member.username;
  2398.                         }
  2399.    
  2400.                         document.getElementById("revoke-modal-title").innerText = "Revoke GitHub Repo from " + name;
  2401.                        
  2402.                         if (!member.github_username) {
  2403.                             // Display the warning message and disable the form
  2404.                             document.getElementById("github-warning").innerHTML =  
  2405.                             name + " has not set their GitHub username. </br> Please ask them to set their github username before revoking repositories.";
  2406.                             document.getElementById("github-warning").style.display = "block";
  2407.                            
  2408.                             // Disable checkboxes and submit button
  2409.                             disableForm(true);
  2410.                         } else {
  2411.                             // Hide the warning message and enable the form
  2412.                             document.getElementById("github-warning").style.display = "none";
  2413.                             disableForm(false);
  2414.                         }
  2415.                     } else {
  2416.                         console.error("Member not found.");
  2417.                     }
  2418.                 }
  2419.                
  2420.                 function disableForm(disable) {
  2421.                     const checkboxes = document.querySelectorAll('.assign-repo-form input[type="checkbox"]');
  2422.                     const submitButton = document.querySelector('.assign-repo-submit-btn');
  2423.                
  2424.                     checkboxes.forEach(checkbox => {
  2425.                         checkbox.disabled = disable;
  2426.                         if (disable) {
  2427.                             checkbox.classList.add('disabled-checkbox'); // Add a class to style disabled checkboxes
  2428.                         } else {
  2429.                             checkbox.classList.remove('disabled-checkbox'); // Remove the class
  2430.                         }
  2431.                     });
  2432.                
  2433.                     submitButton.disabled = disable; // Disable the button
  2434.                     if (disable) {
  2435.                         submitButton.classList.add('disabled-button'); // Add disabled class
  2436.                     } else {
  2437.                         submitButton.classList.remove('disabled-button'); // Remove disabled class
  2438.                     }
  2439.                 }
  2440.                
  2441.                 function closeAssignRepoModal() {
  2442.                     const checkboxes = document.querySelectorAll('#assignRepoModal input[type="checkbox"]');
  2443.                     checkboxes.forEach(checkbox => checkbox.checked = false);
  2444.    
  2445.                     document.getElementById("assignRepoModal").style.display = "none";
  2446.                 }
  2447.    
  2448.                 function closeRevokeRepoModal() {
  2449.                     const checkboxes = document.querySelectorAll('#revokeRepoModal input[type="checkbox"]');
  2450.                     checkboxes.forEach(checkbox => checkbox.checked = false);
  2451.    
  2452.                     document.getElementById("revokeRepoModal").style.display = "none";
  2453.                 }
  2454.    
  2455.                 async function submitAssignRepoForm(event) {
  2456.                     event.preventDefault();
  2457.    
  2458.                     const checkboxes = document.querySelectorAll('input[name="repo"]:checked');
  2459.                     const selectedRepos = Array.from(checkboxes).map(cb => cb.value);
  2460.    
  2461.                     const statusElement = document.getElementById('status-message');
  2462.    
  2463.                     if (selectedRepos.length === 0) {
  2464.                         alert('Please select at least one repository.');
  2465.                         return;
  2466.                     }
  2467.    
  2468.                     try {
  2469.                         for (let repoName of selectedRepos) {
  2470.                             const response = await fetch('/project/assign-repo/', {
  2471.                                 method: 'POST',
  2472.                                 headers: {
  2473.                                     'Content-Type': 'application/json',
  2474.                                 },
  2475.                                 body: JSON.stringify({
  2476.                                     repo_name: repoName,
  2477.                                     user_id: currentUserId,
  2478.                                     projectId : projectId,
  2479.                                 }),
  2480.                             });
  2481.    
  2482.                             const data = await response.json();
  2483.    
  2484.                             if (response.ok) {
  2485.                                 alert(` ${repoName} assigned successfully`);
  2486.                                 closeAssignRepoModal();
  2487.                             } else {
  2488.    
  2489.                                 alert(`Error : ${data.error.message || data.error || 'Unknown error'}`);
  2490.                                
  2491.                             }
  2492.                         }
  2493.                     } catch (error) {
  2494.                         alert(`An error occurred: ${error.message}`);
  2495.                     }
  2496.                 }
  2497.    
  2498.                 async function submitRevokeRepoForm(event) {
  2499.                     event.preventDefault();
  2500.                
  2501.                    
  2502.                     const checkboxes = document.querySelectorAll('input[name="revokerepo"]:checked');
  2503.                     const selectedRepoIds = Array.from(checkboxes).map(cb => cb.value);  
  2504.                
  2505.                     const statusElement = document.getElementById('status-message');
  2506.                
  2507.                     if (selectedRepoIds.length === 0) {
  2508.                         alert('Please select at least one repository.');
  2509.                         return;
  2510.                     }
  2511.                
  2512.                     try {
  2513.                         // Make a single API request with the selected repository IDs and user ID
  2514.                         const response = await fetch('/project/revoke-repo/', {
  2515.                             method: 'POST',
  2516.                             headers: {
  2517.                                 'Content-Type': 'application/json',
  2518.                             },
  2519.                             body: JSON.stringify({
  2520.                                 repo_ids: selectedRepoIds,
  2521.                                 user_id: currentUserId,
  2522.                             }),
  2523.                         });
  2524.                
  2525.                         const data = await response.json();
  2526.                
  2527.                         if (response.ok) {
  2528.                             alert(data.message);
  2529.                             closeRevokeRepoModal();
  2530.                             if (data.errors){
  2531.                                 console.log(data.errors);
  2532.                             }
  2533.                         } else {
  2534.                             if (data.status === 'error' && data.message === 'User not found.') {
  2535.                                 alert('Error: User not found.');
  2536.                             } else if (data.status === 'error' && data.message === 'No repositories found for the provided repository IDs.') {
  2537.                                 alert('Error: No repositories found.');
  2538.                             } else {
  2539.                                 alert(`Error: ${data.message || 'Unknown error occurred.'}`);
  2540.                             }
  2541.                         }
  2542.                     } catch (error) {
  2543.                         alert(`An error occurred: ${error.message}`);
  2544.                     }
  2545.                 }
  2546.                
  2547.             /* MILESTONE CHANGES */
  2548.             function updateMilestoneColor(milestoneElement, status) {
  2549.                 switch (status) {
  2550.                     case 'completed':
  2551.                         milestoneElement.style.backgroundColor = '#50CF66';
  2552.                         milestoneElement.style.color = '#08090A';
  2553.                         break;
  2554.                     case 'on-progress':
  2555.                         milestoneElement.style.backgroundColor = '#FCC418';
  2556.                         milestoneElement.style.color = '#08090A';
  2557.                         break;
  2558.                     default:
  2559.                         milestoneElement.style.backgroundColor = '#CED4DA';
  2560.                         milestoneElement.style.color = '#939CA3';
  2561.                         break;
  2562.                 }
  2563.             }
  2564.  
  2565.             function showMilestonePopup(event) {
  2566.                 const clickedDiv = event.currentTarget;
  2567.                 const milestonePopup = document.getElementById('milestone-action-popup');
  2568.  
  2569.                 const rect = clickedDiv.getBoundingClientRect();
  2570.                 const offsetX = window.scrollX;
  2571.                 const offsetY = window.scrollY;
  2572.  
  2573.                 milestonePopup.style.left = `${(rect.left + offsetX)/zoom}px`;
  2574.                 milestonePopup.style.top = `${(rect.bottom + offsetY)/zoom}px`;
  2575.                 milestonePopup.style.display = 'block';
  2576.  
  2577.                 // store the clicked milestone id in data-attribute
  2578.                 milestonePopup.setAttribute('data-current-milestone', clickedDiv.id);
  2579.  
  2580.                 const handleClickOutside = (event) => {
  2581.                     if (!milestonePopup.contains(event.target) && !clickedDiv.contains(event.target)) {
  2582.                         milestonePopup.style.display = 'none';
  2583.                         document.removeEventListener('click', handleClickOutside);
  2584.                     }
  2585.                 };
  2586.                 document.addEventListener('click', handleClickOutside);
  2587.             }
  2588.  
  2589.             function setMilestoneStatus(status) {
  2590.                 const currentMilestoneId = document.getElementById('milestone-action-popup').getAttribute('data-current-milestone');
  2591.  
  2592.                 if (currentMilestoneId) {
  2593.                     milestoneStatuses[currentMilestoneId].status = status;
  2594.  
  2595.                     const milestoneElement = document.getElementById(currentMilestoneId);
  2596.                     updateMilestoneColor(milestoneElement, status);
  2597.  
  2598.              
  2599.  
  2600.                     // hide the popup after updating
  2601.                     document.getElementById('milestone-action-popup').style.display = 'none';
  2602.                     fetch('/project/update_milestone/', {
  2603.                         method: 'POST',
  2604.                         headers: {
  2605.                             'Content-Type': 'application/json',
  2606.                            
  2607.                         },
  2608.                         body: JSON.stringify({
  2609.                             milestoneStatuses: milestoneStatuses,
  2610.                             project_id: projectId
  2611.                         })
  2612.                     })
  2613.                     .then(response => response.json())
  2614.                     .then(data => {
  2615.                         if (data.status === 'success') {
  2616.                             window.location.reload();
  2617.                             console.log('Milestone statuses updated successfully.');
  2618.                         } else {
  2619.                             console.error('Error:', data.message);
  2620.                         }
  2621.                     })
  2622.                     .catch(error => console.error('Error:', error));
  2623.                 }
  2624.             }
  2625.  
  2626.             /* ADDING NEW LINKS */
  2627.             function addNewUrl() {
  2628.                 // Create the new link-add div elements dynamically
  2629.                 const newLinkAddDiv = document.createElement('div');
  2630.                 const newLinkNameInput = document.createElement('input');
  2631.                 const newUrlInput = document.createElement('input');
  2632.                 const removeButton = document.createElement('div');
  2633.  
  2634.                 // Set class and attributes
  2635.                 newLinkAddDiv.className = 'link-add';
  2636.                 newLinkNameInput.type = 'text';
  2637.                 newLinkNameInput.placeholder = 'Add Link name';
  2638.                 newUrlInput.type = 'text';
  2639.                 newUrlInput.placeholder = 'Add URL';
  2640.                 removeButton.className = 'remove-button';
  2641.                 removeButton.textContent = 'x';
  2642.                 removeButton.onclick = (event) => removeThisUrl(event);
  2643.  
  2644.                 // append inputs and remove button to link-add div
  2645.                 newLinkAddDiv.appendChild(newLinkNameInput);
  2646.                 newLinkAddDiv.appendChild(newUrlInput);
  2647.                 newLinkAddDiv.appendChild(removeButton);
  2648.  
  2649.                 // find the link-list div and append new link-add div to it
  2650.                 const linkList = document.getElementById('link-list');
  2651.                 linkList.appendChild(newLinkAddDiv);
  2652.  
  2653.                 // show the save button
  2654.                 document.getElementById('save-button').style.display = 'inline-block';
  2655.             }
  2656.  
  2657.  
  2658.             ////function for remove url added
  2659.             function removeThisUrl(event) {
  2660.                 // find the link-aadd div that contains the remove button
  2661.                 const linkAddDiv = event.target.parentElement;
  2662.  
  2663.                 // remve the div
  2664.                 linkAddDiv.parentNode.removeChild(linkAddDiv);
  2665.  
  2666.                 // hide the save button if no link-add divs are present
  2667.                 const linkList = document.getElementById('link-list');
  2668.                 if (linkList.children.length === 0) {
  2669.                     document.getElementById('save-button').style.display = 'none';
  2670.                 }
  2671.             }
  2672.  
  2673.  
  2674.             //function for saving new links
  2675.             function saveNewLinks() {
  2676.                 const linkList = document.getElementById('link-list');
  2677.                 const documentList = document.getElementById('document-list');
  2678.  
  2679.                 linkList.querySelectorAll('.link-add').forEach(linkAddDiv => {
  2680.                     const linkName = linkAddDiv.querySelector('input[placeholder="Add Link name"]').value;
  2681.                     const linkUrl = linkAddDiv.querySelector('input[placeholder="Add URL"]').value;
  2682.  
  2683.                     if (linkName && linkUrl) {
  2684.                         // ceate new link element
  2685.                         const newLinkDiv = document.createElement('div');
  2686.                         newLinkDiv.style.display = 'flex';
  2687.                         newLinkDiv.style.justifyContent = 'space-between';
  2688.  
  2689.                         const newLink = document.createElement('a');
  2690.                         newLink.href = linkUrl;
  2691.                         newLink.style.textDecoration = 'underline';
  2692.                         newLink.style.color = '#2F6CE5';
  2693.                         newLink.target = '_blank';
  2694.                         newLink.textContent = linkName;
  2695.  
  2696.                         const timeAgo = document.createElement('div');
  2697.                         timeAgo.style.color = '#939CA3';
  2698.                         timeAgo.textContent = 'Just now';
  2699.  
  2700.                         newLinkDiv.appendChild(newLink);
  2701.                         newLinkDiv.appendChild(timeAgo);
  2702.                         documentList.appendChild(newLinkDiv);
  2703.  
  2704.  
  2705.                         fetch('/project/addnewlink/', {
  2706.                             method: 'POST',
  2707.                             headers: {
  2708.                                 'Content-Type': 'application/json',
  2709.  
  2710.                             },
  2711.                             body: JSON.stringify({
  2712.                                 link_name: linkName,
  2713.                                 link_url: linkUrl,
  2714.                                 project_id: "{{project_detail.id}}"
  2715.                             })
  2716.                         })
  2717.  
  2718.                             .then(response => response.json())
  2719.                             .then(data => {
  2720.                                 if (data.status === 'success') {
  2721.                                     console.log('Link saved successfully.');
  2722.                                 } else {
  2723.                                     console.error('Error saving link:', data.error);
  2724.                                 }
  2725.                             })
  2726.                             .catch(error => {
  2727.                                 console.error('Error:', error);
  2728.                             });
  2729.                     }
  2730.                 });
  2731.  
  2732.  
  2733.                 // hide the link list and save button
  2734.                 linkList.innerHTML = '';
  2735.             }
  2736.  
  2737.  
  2738.  
  2739.             /* EMAIL TEMPLATES */
  2740.             function preSprintDocEmailTemplate() {
  2741.                 let template = document.getElementById('pre-sprint-doc-email-template').innerText;
  2742.                 // template = template.replace(/\s+/g, ' ').trim();
  2743.  
  2744.                 const link = "https://www.figma.com/design/re7NRY22F5JxDITK8z59Rv/3262-%3A-Intranet---Banao-integration-to-Intranet?node-id=3843-8124&node-type=frame&t=4h98xXAjCTNxycRa-0"
  2745.                 template = `Greetings from Banao Technologies!\n\n` +
  2746.                     `This is to inform you that we are kick-starting the development hereon 18.09.2023 and starting with the first iterations of designs.\n\n` +
  2747.                     `PFA the link to the PSD : ${link}\n\n` +
  2748.                     `    β€’    The main objective of this document is to get further clarity on the existing agreed upon flow/expectations, especially wrt the design and flow expectations.\n` +
  2749.                     `    β€’    These documents will have niche details regarding the next sprint/milestone (adhering to the scope in the original proposal).\n` +
  2750.                     `    β€’    Anything that is not part of this document will be considered a change request during the execution of the milestone/sprint later on.\n` +
  2751.                     `    β€’    The common things that are missed out by the clients in initial requirements include:\n` +
  2752.                     `            β€’ Loading, Error, New User (Empty) states\n` +
  2753.                     `            β€’ User specific logics.\n` +
  2754.                     `    β€’    Prefer to add your text in a different font/colour.\n\n` +
  2755.                     `A pre-sprint discussion will happen soon and we will ask for clarity on the points and flag any of the niche points during the discussion later in case they fall outside the scope (confirming to the proposal/FRD).\n\n` +
  2756.                     `Looking Forward to connecting over a call.\n` +
  2757.                     `Please feel free to put your queries and I’d be happy to assist with.\n\n` +
  2758.                     `Regards,\n\n` +
  2759.                     `Rishi\n` +
  2760.                     `Project Manager,\n` +
  2761.                     `Banao Technologies\n` +
  2762.                     `(https://banao.tech/)`;
  2763.              
  2764.                 navigator.clipboard.writeText(template).then(function () {
  2765.                     alert("Email template copied to clipboard!");
  2766.                 }, function (err) {
  2767.                     alert("Error copying template: " + err);
  2768.                 });
  2769.             }
  2770.  
  2771.             function closeEmailTemplate() {
  2772.                 document.getElementById("pre-sprint-doc-email-modal").style.display = "none";
  2773.             }
  2774.  
  2775.            
  2776.             function designConfirmationEmailTemplate() {
  2777.                 let template = document.getElementById('design-confirmation-email-template').innerText;
  2778.                 navigator.clipboard.writeText(template).then(function () {
  2779.                     alert("Email template copied to clipboard!");
  2780.                 }, function (err) {
  2781.                     alert("Error copying template: " + err);
  2782.                 });
  2783.             }
  2784.  
  2785.             function closedesignConfirmationEmailTemplate() {
  2786.                 document.getElementById("design-confirmation-email-modal").style.display = "none";
  2787.             }
  2788.  
  2789.             function designLockEmailTemplate() {
  2790.                 let template = document.getElementById('design-lock-email-template').innerText;
  2791.                 navigator.clipboard.writeText(template).then(function () {
  2792.                     alert("Email template copied to clipboard!");
  2793.                 }, function (err) {
  2794.                     alert("Error copying template: " + err);
  2795.                 });
  2796.             }
  2797.  
  2798.             function closedesignLockEmailTemplate() {
  2799.                 document.getElementById("design-lock-email-modal").style.display = "none";
  2800.             }
  2801.  
  2802.             function milestoneTimelineEmailTemplate() {
  2803.                 let template = document.getElementById('milestone-timeline-email-template').innerText;
  2804.                 navigator.clipboard.writeText(template).then(function () {
  2805.                     alert("Email template copied to clipboard!");
  2806.                 }, function (err) {
  2807.                     alert("Error copying template: " + err);
  2808.                 });
  2809.             }
  2810.  
  2811.             function closeMilestoneTimelineEmailTemplate() {
  2812.                 document.getElementById("milestone-timeline-email-modal").style.display = "none";
  2813.             }
  2814.  
  2815.             function milestoneClosureEmailTemplate() {
  2816.                 let template = document.getElementById('milestone-closure-email-template').innerText;
  2817.                 navigator.clipboard.writeText(template).then(function () {
  2818.                     alert("Email template copied to clipboard!");
  2819.                 }, function (err) {
  2820.                     alert("Error copying template: " + err);
  2821.                 });
  2822.             }
  2823.  
  2824.             function closeMilestoneClosureEmailTemplate() {
  2825.                 document.getElementById("milestone-closure-email-modal").style.display = "none";
  2826.             }
  2827.  
  2828.             function projectClosureEmailTemplate() {
  2829.                 let template = document.getElementById('project-closure-email-template').innerText;
  2830.                 // template = template.replace(/\s+/g, ' ').trim();
  2831.  
  2832.                 navigator.clipboard.writeText(template).then(function () {
  2833.                     alert("Email template copied to clipboard!");
  2834.                 }, function (err) {
  2835.                     alert("Error copying template: " + err);
  2836.                 });
  2837.             }
  2838.  
  2839.             function closeProjectClosureEmailTemplate() {
  2840.                 document.getElementById("project-closure-email-modal").style.display = "none";
  2841.             }
  2842.  
  2843.             function supportPeriodEmailTemplate() {
  2844.                 let template = document.getElementById('support-period-email-template').innerText;
  2845.                 // template = template.replace(/\s+/g, ' ').trim();
  2846.  
  2847.            
  2848.                 navigator.clipboard.writeText(template).then(function () {
  2849.                     alert("Email template copied to clipboard!");
  2850.                 }, function (err) {
  2851.                     alert("Error copying template: " + err);
  2852.                 });
  2853.             }
  2854.  
  2855.             function closeSupportPeriodEmailTemplate() {
  2856.                 document.getElementById("support-period-email-modal").style.display = "none";
  2857.             }
  2858.            
  2859.             /* Internal tasks funcs */
  2860.  
  2861.             function formatDateForInput(dateString) {
  2862.                 if (!dateString) return ''; // Return empty if no date provided
  2863.            
  2864.                 // Parse the date from the string (assuming it's in ISO or valid date format)
  2865.                 let date = new Date(dateString);
  2866.            
  2867.                 // Extract the year, month (note: JS months are zero-indexed), and day
  2868.                 let year = date.getFullYear();
  2869.                 let month = ('0' + (date.getMonth() + 1)).slice(-2); // Add 1 to month since it's zero-indexed
  2870.                 let day = ('0' + date.getDate()).slice(-2); // Pad with leading zero if necessary
  2871.            
  2872.                 // Return formatted as YYYY-MM-DD
  2873.                 return `${year}-${month}-${day}`;
  2874.             }
  2875.  
  2876.             function deleteTask(deleteBtn, taskId) {
  2877.                 const row = deleteBtn.closest('tr');
  2878.                 const parentTaskId = row.getAttribute('data-task-id');
  2879.                
  2880.                 const confirmDelete = confirm('Are you sure you want to delete this task?  Note: All subtasks will be deleted (if any)');
  2881.                 if (!confirmDelete) {
  2882.                     return;
  2883.                 }
  2884.  
  2885.                 fetch(`/project/delete-task/`, {
  2886.                     method: 'POST',
  2887.                     headers: {
  2888.                         'Content-Type': 'application/json',
  2889.                     },
  2890.                     body: JSON.stringify({
  2891.                         task_id: taskId,
  2892.                     })
  2893.                 })
  2894.                 .then(response => response.json())
  2895.                 .then(data => {
  2896.                     if (data.status === 'success') {
  2897.                         // If this is a subtask
  2898.                         if (row.classList.contains('subtask-row')) {
  2899.                             // Only remove this specific subtask row
  2900.                             row.remove();
  2901.                            
  2902.                             // Update parent task's subtask count and status
  2903.                             if (parentTaskId) {
  2904.                                 const parentRow = document.getElementById(parentTaskId);
  2905.                                 const subtaskCountSpan = parentRow.querySelector('.subtask-count');
  2906.                                 let currentCount = parseInt(subtaskCountSpan.textContent.replace(/\D/g, '')) || 0;
  2907.                                 currentCount--;
  2908.                                 subtaskCountSpan.textContent = `(${currentCount})`;
  2909.                                
  2910.                                 // Update the parent task's progress
  2911.                                 updateProgress(parentRow);
  2912.                                
  2913.                                 // If this was the last subtask, hide the toggle arrow
  2914.                                 if (currentCount === 0) {
  2915.                                     const toggleSvg = parentRow.querySelector('#togglesvg');
  2916.                                     const checkbox = parentRow.querySelector('.circular-checkbox');
  2917.                                     if (toggleSvg) {
  2918.                                         toggleSvg.style.display = 'none';
  2919.                                     }
  2920.                                     if (checkbox) {
  2921.                                         checkbox.style.display = 'block';
  2922.                                     }
  2923.                                 }
  2924.                             }
  2925.                         } else {
  2926.                             // This is a main task - remove it and all its subtasks
  2927.                             let nextRow = row.nextElementSibling;
  2928.                             row.remove();
  2929.                            
  2930.                             while (nextRow && nextRow.classList.contains('subtask-row') &&
  2931.                                 nextRow.getAttribute('data-task-id') === taskId) {
  2932.                                 const rowToRemove = nextRow;
  2933.                                 nextRow = nextRow.nextElementSibling;
  2934.                                 rowToRemove.remove();
  2935.                             }
  2936.                         }
  2937.                     } else {
  2938.                         alert('Error deleting task: ' + data.message);
  2939.                     }
  2940.                 })
  2941.                 .catch(error => {
  2942.                     console.error('Error:', error);
  2943.                     alert('Error deleting task.');
  2944.                 });
  2945.             }
  2946.            
  2947.             function saveTask(saveBtn) {
  2948.                 let row = saveBtn.closest('tr');
  2949.                
  2950.                 let taskId = row.id; // Assuming the row's id is the task id
  2951.                 let newName = row.querySelector('.edit-task-name').value.trim() || 'Unnamed task'; // Default to "Unnamed task" if blank
  2952.                 let newAssignee = row.querySelector('.assignee-input select').value || 'Unassigned'; // Default to 'Unassigned'
  2953.                
  2954.                 let newDueDate = row.querySelector('.edit-due-date').value || ''; // Allow empty due date
  2955.                 let newBounties = row.querySelector('.edit-bounties').value.trim() || '0'; // Default to '0' if blank
  2956.            
  2957.                 // Perform the AJAX request (or other save logic)
  2958.                 fetch(`/project/update-task/`, {
  2959.                     method: 'POST',
  2960.                     headers: {
  2961.                         'Content-Type': 'application/json',
  2962.                     },
  2963.                     body: JSON.stringify({
  2964.                         task_id: taskId,
  2965.                         task_name: newName,
  2966.                         assignee: newAssignee,
  2967.                         due_date: newDueDate,
  2968.                         bounties: newBounties
  2969.                     })
  2970.                 })
  2971.                 .then(response => response.json())
  2972.                 .then(data => {
  2973.                     if (data.status === 'success') {
  2974.                         // Replace the input fields with updated values
  2975.                         let assigneeName = 'Unassigned';
  2976.                         let assignee = team_members.find(member => member.id == newAssignee);
  2977.                         if (assignee) {
  2978.                             assigneeName = assignee.name; // Extract name from team_members array
  2979.                         }
  2980.  
  2981.                         row.querySelector('.task-name').innerHTML = newName || 'Unnamed task'; // Default display if empty
  2982.                         row.querySelector('.assignee-input').innerHTML = assigneeName || 'Unassigned'; // Display 'Unassigned' if empty
  2983.                         if (newDueDate){
  2984.                             row.querySelector('.date-input').value = newDueDate || ''; // Leave empty if no date
  2985.                         }
  2986.                        
  2987.                         row.querySelector('.bountie-input').innerHTML = newBounties || '1'; // Default to '0' if empty
  2988.            
  2989.                         // Replace the save button with the pen icon again
  2990.                         saveBtn.parentElement.outerHTML = `
  2991.                         <svg class="edit-task-svg" onclick="makeTaskEditable(this)" style="cursor: pointer;" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  2992.                             <path d="M2 16.5V21H6.5L18.51 8.99L14.01 4.49L2 16.5ZM22.41 7.34C22.8 6.95 22.8 6.32 22.41 5.93L18.07 1.59C17.68 1.2 17.05 1.2 16.66 1.59L14.91 3.34L20.66 9.09L22.41 7.34Z" fill="#6D747A"/>
  2993.                         </svg>`;
  2994.                     } else {
  2995.                         alert('Error saving task');
  2996.                     }
  2997.                 })
  2998.                 .catch(error => {
  2999.                     console.error('Error:', error);
  3000.                 });
  3001.             }
  3002.            
  3003.             function getInitials(username) {
  3004.                 const nameParts = username.trim().split(/\s+/);
  3005.                 return nameParts.map(part => part[0].toUpperCase()).join('');
  3006.             }
  3007.            
  3008.             function createInitialsCircle(initials, username, assignIcon,taskId) {
  3009.                 const circle = document.createElement('div');
  3010.                 circle.className = 'initials-circle';
  3011.                 circle.style.width = '25px';
  3012.                 circle.style.height = '25px';
  3013.                 circle.style.borderRadius = '50%';
  3014.                 circle.style.display = 'flex';
  3015.                 circle.style.alignItems = 'center';
  3016.                
  3017.                 circle.style.justifyContent = 'center';
  3018.                 circle.style.backgroundColor = '#7c4dff';
  3019.                 circle.style.color = '#fff';
  3020.                 circle.style.cursor = 'pointer';
  3021.                 circle.style.fontSize = '14px';
  3022.                 circle.textContent = initials;
  3023.            
  3024.                 assignIcon.innerHTML = '';
  3025.                 assignIcon.appendChild(circle);
  3026.                 assignIcon.title = username;
  3027.                 assignIcon.style.margin = "2px";
  3028.                 assignIcon.addEventListener('click', () => openAssigneeDropdown(taskId,assignIcon));
  3029.             }
  3030.            
  3031.             function openAssigneeDropdown(taskId, button) {
  3032.                 const existingDropdown = document.querySelector('.custom-dropdown');
  3033.                 if (existingDropdown) {
  3034.                     existingDropdown.remove();
  3035.                     return;
  3036.                 }
  3037.                 if (taskId == "none"){
  3038.                     taskId = currentTaskId;
  3039.                 }
  3040.                
  3041.            
  3042.                 let dropdown = document.createElement('div');
  3043.                 dropdown.className = 'custom-dropdown';
  3044.                 dropdown.style.position = 'absolute';
  3045.                 dropdown.style.background = 'white';
  3046.                 dropdown.style.border = '1px solid #ddd';
  3047.                 dropdown.style.padding = '5px';
  3048.                 dropdown.style.zIndex = '1000';
  3049.                 dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  3050.                 dropdown.style.maxHeight = '200px';
  3051.                 dropdown.style.overflowY = 'auto';
  3052.            
  3053.                 let searchInput = document.createElement('input');
  3054.                 searchInput.type = 'text';
  3055.                 searchInput.placeholder = 'Search team members';
  3056.                 searchInput.id="search-team-members";
  3057.                 searchInput.style.width = '100%';
  3058.                 searchInput.style.padding = '5px';
  3059.                 searchInput.style.border = '1px solid #ddd';
  3060.                 searchInput.style.boxSizing = 'border-box';
  3061.                 searchInput.style.marginBottom = '10px';
  3062.            
  3063.                 dropdown.appendChild(searchInput);
  3064.            
  3065.                 let memberList = document.createElement('div');
  3066.                 dropdown.appendChild(memberList);
  3067.            
  3068.                 team_members.forEach(member => {
  3069.                     const memberItem = document.createElement('div');
  3070.                     memberItem.textContent = member.name;
  3071.                     memberItem.style.padding = '5px 10px';
  3072.                     memberItem.style.cursor = 'pointer';
  3073.                     memberItem.style.backgroundColor = 'white';
  3074.            
  3075.                     memberItem.addEventListener('mouseover', () => {
  3076.                         memberItem.style.backgroundColor = '#f1f1f1';
  3077.                     });
  3078.                     memberItem.addEventListener('mouseout', () => {
  3079.                         memberItem.style.backgroundColor = 'white';
  3080.                     });
  3081.            
  3082.                     memberItem.addEventListener('click', () => {
  3083.                         const initials = getInitials(member.name);
  3084.                         createInitialsCircle(initials, member.name, button, taskId);
  3085.                         selectedMember = member.name;
  3086.                         selectedMemberData = {"id": member.id, "name": member.name};
  3087.                        
  3088.                         fetch('/project/save-assignee/', {
  3089.                             method: 'POST',
  3090.                             headers: {
  3091.                                 'Content-Type': 'application/json',
  3092.                             },
  3093.                             body: JSON.stringify({ taskId: taskId, assigneeId: member.id })
  3094.                         })
  3095.                         .then(response => response.json())
  3096.                         .then(data => {
  3097.                             if (data.success) {
  3098.                                 console.log('Assignee saved successfully');
  3099.                             } else {
  3100.                                 console.error('Failed to save assignee');
  3101.                             }
  3102.                         })
  3103.                         .catch(error => {
  3104.                             console.error('Error:', error);
  3105.                         });
  3106.            
  3107.                         dropdown.remove();
  3108.                     });
  3109.            
  3110.                     memberList.appendChild(memberItem);
  3111.                 });
  3112.            
  3113.                 const rect = button.getBoundingClientRect();
  3114.                 dropdown.style.left = `${rect.left}px`;
  3115.                 dropdown.style.top = `${rect.bottom + window.scrollY}px`;
  3116.            
  3117.                 document.body.appendChild(dropdown);
  3118.            
  3119.                 const handleClickOutside = (event) => {
  3120.                     if(event.target.id!="search-team-members"){
  3121.                         if (!button.contains(event.target)) {
  3122.                             dropdown.remove();
  3123.                             document.removeEventListener('click', handleClickOutside);
  3124.                         }
  3125.                     }
  3126.                 };
  3127.                 document.addEventListener('click', handleClickOutside);
  3128.            
  3129.                 searchInput.addEventListener('input', function () {
  3130.                     const query = searchInput.value.toLowerCase();
  3131.                     const items = memberList.querySelectorAll('div');
  3132.                     items.forEach(item => {
  3133.                         const text = item.textContent.toLowerCase();
  3134.                         if (text.indexOf(query) === -1) {
  3135.                             item.style.display = 'none';
  3136.                         } else {
  3137.                             item.style.display = 'block';
  3138.                         }
  3139.                     });
  3140.                 });
  3141.            
  3142.                 const clearButton = document.createElement('button');
  3143.                 clearButton.textContent = 'Clear';
  3144.                 clearButton.style.padding = '5px 10px';
  3145.                 clearButton.style.marginTop = '10px';
  3146.                 clearButton.style.cursor = 'pointer';
  3147.                 clearButton.style.border = 'none';
  3148.                 clearButton.style.background = "lightgrey";
  3149.            
  3150.                 clearButton.addEventListener('click', () => {
  3151.                     selectedMember = null;
  3152.                     selectedMemberData = {};
  3153.                     button.title = "select assignee";
  3154.                     fetch('/project/save-assignee/', {
  3155.                         method: 'POST',
  3156.                         headers: {
  3157.                             'Content-Type': 'application/json',
  3158.                         },
  3159.                         body: JSON.stringify({ taskId: taskId, assigneeId: "none" })
  3160.                     })
  3161.                     .then(response => response.json())
  3162.                     .then(data => {
  3163.                         if (data.success) {
  3164.                             console.log('Assignee saved successfully');
  3165.                         } else {
  3166.                             console.error('Failed to save assignee');
  3167.                         }
  3168.                     })
  3169.                     .catch(error => {
  3170.                         console.error('Error:', error);
  3171.                     });
  3172.                     button.innerHTML =
  3173.                     `<svg class="assignee-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="width: 24px; height: 24px; fill: #ABABAB;">
  3174.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  3175.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  3176.                                                     <g id="SVGRepo_iconCarrier">
  3177.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" />
  3178.                                                     </g>
  3179.                                            
  3180.                                                 </svg>`
  3181.                     dropdown.remove();
  3182.                    
  3183.                 });
  3184.                 button.addEventListener('click', () => openAssigneeDropdown(taskId,button));
  3185.                 dropdown.appendChild(clearButton);
  3186.                
  3187.             }
  3188.            
  3189.             function openPriorityDropdown(taskId, button) {
  3190.                 // Check if the dropdown is already visible and remove it
  3191.                 const existingDropdown = document.querySelector('.custom-dropdown');
  3192.                 if (existingDropdown) {
  3193.                     existingDropdown.remove();
  3194.                     return; // Don't create a new dropdown if one is already visible
  3195.                 }
  3196.  
  3197.                 // Create the custom dropdown for priority options
  3198.                 let dropdown = document.createElement('div');
  3199.                 dropdown.className = 'custom-dropdown';
  3200.                 dropdown.style.position = 'absolute';
  3201.                 dropdown.style.background = 'white';
  3202.                 dropdown.style.border = '1px solid #ddd';
  3203.                 dropdown.style.padding = '5px';
  3204.                 dropdown.style.zIndex = '1000';
  3205.                 dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  3206.                 dropdown.style.maxHeight = '200px';
  3207.                 dropdown.style.overflowY = 'auto';
  3208.                 dropdown.style.minWidth = '200px';
  3209.  
  3210.                 // Define the priority options
  3211.                 const priorities = {
  3212.                     urgent: "Urgent",
  3213.                     high: "High",
  3214.                     normal: "Normal",
  3215.                     low: "Low"
  3216.                 };
  3217.  
  3218.                 // Create the dropdown options
  3219.                 Object.keys(priorities).forEach(priority => {
  3220.                     const option = document.createElement('div');
  3221.                     option.textContent = priorities[priority];
  3222.                     option.style.padding = '5px 10px';
  3223.                     option.style.cursor = 'pointer';
  3224.                     option.style.backgroundColor = 'white';
  3225.  
  3226.                     // Hover effect for the dropdown items
  3227.                     option.addEventListener('mouseover', () => {
  3228.                         option.style.backgroundColor = '#f1f1f1';
  3229.                     });
  3230.                     option.addEventListener('mouseout', () => {
  3231.                         option.style.backgroundColor = 'white';
  3232.                     });
  3233.  
  3234.                     // When an option is selected, update the flag color
  3235.                     option.addEventListener('click', () => {
  3236.                         selectedPriority = priority;
  3237.                         const svgElement = button.querySelector('svg');
  3238.                        
  3239.                         // Select the paths inside the SVG
  3240.                         const priorityIconPath = svgElement.querySelector('#priority-icon-path');
  3241.                         const priorityIconExc = svgElement.querySelector('#priority-iconborder');
  3242.                         const priorityOutline = svgElement.querySelector('#priority-icon-exclamation');
  3243.  
  3244.                         // Define color changes for different priorities
  3245.                         const colors = {
  3246.                             urgent: "red",
  3247.                             high: "gold",
  3248.                             normal: "transparent",
  3249.                             low: "grey"
  3250.                         };
  3251.  
  3252.                         // Change the color of the flag icon based on selected priority
  3253.                         if (selectedPriority !== "none") {
  3254.                             priorityIconPath.setAttribute('fill', colors[selectedPriority]);
  3255.                             priorityIconPath.setAttribute('stroke',colors[selectedPriority]);
  3256.                             if (colors[selectedPriority] == "red" )
  3257.                             {
  3258.                                
  3259.                                 priorityOutline.setAttribute('stroke', 'white');
  3260.                             }
  3261.                             else if (colors[selectedPriority] == "transparent"){
  3262.                                 priorityOutline.setAttribute('stroke', 'grey');
  3263.                                 priorityIconPath.setAttribute('stroke', 'grey');
  3264.                             }
  3265.                             else{
  3266.                                
  3267.                                 priorityOutline.setAttribute('stroke', 'black');
  3268.                             }
  3269.                            
  3270.                         }
  3271.  
  3272.                         // Remove the dropdown after selection
  3273.                         dropdown.remove();
  3274.                         fetch('/project/update-priority/', {
  3275.                             method: 'POST',
  3276.                             headers: {
  3277.                                 'Content-Type': 'application/json',
  3278.                             },
  3279.                             body: JSON.stringify({
  3280.                                 taskId: taskId,
  3281.                                 priority: selectedPriority
  3282.                             })
  3283.                         })
  3284.                         .then(response => response.json())
  3285.                         .then(data => {
  3286.                             console.log('Priority updated successfully', data);
  3287.                         })
  3288.                         .catch(error => {
  3289.                             console.error('Error updating priority:', error);
  3290.                         });
  3291.            
  3292.                        
  3293.                     });
  3294.                    
  3295.  
  3296.                     dropdown.appendChild(option);
  3297.                 });
  3298.  
  3299.                 // Create a "Clear" button as part of the dropdown
  3300.                 const clearButton = document.createElement('button');
  3301.                 clearButton.textContent = 'Clear';
  3302.                 clearButton.style.padding = '5px 10px';
  3303.                 clearButton.style.marginTop = '10px';
  3304.                 clearButton.style.cursor = 'pointer';
  3305.                 clearButton.style.border = 'none';
  3306.                 clearButton.style.background = "lightgrey";
  3307.  
  3308.                 // When the "Clear" button is clicked, reset to original state
  3309.                 clearButton.addEventListener('click', () => {
  3310.                     const priorityIconPath = document.getElementById('priority-icon-path');
  3311.                     priorityIconPath.setAttribute('fill', "blue");
  3312.                     priorityIconPath.setAttribute('stroke', "blue");
  3313.                    
  3314.                     // Remove the dropdown after clicking "Clear"
  3315.                     dropdown.remove();
  3316.                     fetch('/project/update-priority/', {
  3317.                         method: 'POST',
  3318.                         headers: {
  3319.                             'Content-Type': 'application/json',
  3320.                         },
  3321.                         body: JSON.stringify({
  3322.                             taskId: taskId,
  3323.                             priority: 'normal'
  3324.                         })
  3325.                     })
  3326.                     .then(response => response.json())
  3327.                     .then(data => {
  3328.                         console.log('Priority updated successfully', data);
  3329.                     })
  3330.                     .catch(error => {
  3331.                         console.error('Error updating priority:', error);
  3332.                     });
  3333.                 });
  3334.  
  3335.                 dropdown.appendChild(clearButton);
  3336.  
  3337.                 // Position the dropdown below the icon
  3338.                 const rect = button.getBoundingClientRect();
  3339.                 const zoomFactor = 1; // Optional zoom adjustment
  3340.  
  3341.                 dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  3342.                 dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  3343.  
  3344.                 document.body.appendChild(dropdown);
  3345.                 const handleClickOutside = (event) => {
  3346.                     if (!button.contains(event.target)) {
  3347.                         dropdown.remove();
  3348.                         document.removeEventListener('click', handleClickOutside);
  3349.                     }
  3350.                 };
  3351.                 document.addEventListener('click', handleClickOutside);
  3352.  
  3353.             }
  3354.             function openDueDateDropdown(taskId, dateIcon) {
  3355.                 // Check if the date picker is already visible and remove it
  3356.                 const existingDropdown = document.querySelector('.date-picker-dropdown');
  3357.                 if (existingDropdown) {
  3358.                     existingDropdown.remove();
  3359.                     return;
  3360.                 }
  3361.                 if (taskId == "none"){
  3362.                     taskId = currentTaskId;
  3363.                 }
  3364.  
  3365.                 // Create the date input field (it will appear as a dropdown)
  3366.                 const dateInput = document.createElement('input');
  3367.                 dateInput.type = 'date';
  3368.                 dateInput.className = 'date-icon-input';
  3369.  
  3370.                 dateInput.addEventListener('change', function () {
  3371.                     selectedDate = new Date(this.value);
  3372.                     const formattedDate = selectedDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: '2-digit' });
  3373.                    
  3374.                     // Update the icon's HTML with the selected date
  3375.                     dateIcon.innerHTML = `${formattedDate}`;
  3376.                     dateIcon.offsetWidth;  
  3377.                     dateIcon.style.width = "auto";
  3378.                     dateIcon.style.minWidth = "100px";
  3379.                    
  3380.                     // Check if this is a checkpoint task and update flag color if needed
  3381.                     const row = dateIcon.closest('tr');
  3382.                     if (row && row.classList.contains('task-row-checkpoint')) {
  3383.                         const flagIcon = row.querySelector('.flag-icon svg path');
  3384.                         if (flagIcon) {
  3385.                             const today = new Date();
  3386.                             today.setHours(0, 0, 0, 0);
  3387.                            
  3388.                             // If task is marked incomplete (not green)
  3389.                             if (flagIcon.getAttribute('fill') !== 'green') {
  3390.                                 // Update color based on the new date
  3391.                                 if (selectedDate > today) {
  3392.                                     flagIcon.setAttribute('fill', 'grey'); // Future date = grey
  3393.                                 } else {
  3394.                                     flagIcon.setAttribute('fill', '#DD1D43'); // Past date = red
  3395.                                 }
  3396.                             }
  3397.                         }
  3398.                     }
  3399.                    
  3400.                     // Hide the dropdown after date selection
  3401.                     dropdown.remove();
  3402.                 });
  3403.  
  3404.                 // Create a dropdown container for the date input field
  3405.                 const dropdown = document.createElement('div');
  3406.                 dropdown.classList.add('date-picker-dropdown', 'input-style');
  3407.                 dropdown.style.position = 'absolute';
  3408.                 dropdown.style.zIndex = '9999';  
  3409.                 dropdown.style.width = "200px";
  3410.                 const rect = dateIcon.getBoundingClientRect();
  3411.                 const zoomFactor = 1;
  3412.  
  3413.                 dropdown.style.left = `${rect.left / zoomFactor}px`;
  3414.                 dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`;
  3415.  
  3416.                 dropdown.appendChild(dateInput);
  3417.  
  3418.                 // Create a "Clear" button in the next row
  3419.                 const clearButton = document.createElement('button');
  3420.                 clearButton.textContent = 'Clear';
  3421.                 clearButton.classList.add('clear-button');
  3422.                 clearButton.style.marginTop = '10px';
  3423.                 clearButton.style.padding = '5px 10px';
  3424.                 clearButton.style.cursor = 'pointer';
  3425.                 clearButton.style.backgroundColor = '#f0f0f0';
  3426.                 clearButton.style.border = '1px solid #ddd';
  3427.                 clearButton.style.borderRadius = '4px';
  3428.                 clearButton.style.fontSize = '14px';
  3429.  
  3430.                 clearButton.addEventListener('click', () => {
  3431.                     fetch('/project/update-duedate/', {
  3432.                         method: 'POST',
  3433.                         headers: {
  3434.                             'Content-Type': 'application/json',
  3435.                         },
  3436.                         body: JSON.stringify({
  3437.                             taskId: taskId,
  3438.                             date: ""
  3439.                         })
  3440.                     })
  3441.                     .then(response => response.json())
  3442.                     .then(data => {
  3443.                         if (data.success) {
  3444.                             dateInput.value = '';
  3445.                             dateIcon.style.width = "35px";
  3446.                             dateIcon.style.minWidth = "35px";
  3447.                             dateIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  3448.                                 <g id="SVGRepo_iconCarrier">
  3449.                                     <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  3450.                                 </g>
  3451.                             </svg>`;
  3452.                             dropdown.remove();
  3453.                         } else {
  3454.                             alert('Failed to clear due date. Please try again.');
  3455.                         }
  3456.                     })
  3457.                     .catch(error => {
  3458.                         console.error('Error clearing due date:', error);
  3459.                         alert('Failed to clear due date. Please try again.');
  3460.                     });
  3461.                 });
  3462.                 const row = dateIcon.closest('tr');
  3463.                 if (row && row.classList.contains('task-row-checkpoint')) {
  3464.                     const flagIcon = row.querySelector('.flag-icon svg path');
  3465.                     if (flagIcon && flagIcon.getAttribute('fill') !== 'green') {
  3466.                         // No date = red by default
  3467.                         flagIcon.setAttribute('fill', '#DD1D43');
  3468.                     }
  3469.                 }
  3470.  
  3471.                 dropdown.appendChild(clearButton);
  3472.  
  3473.                 document.body.appendChild(dropdown);
  3474.  
  3475.                 const handleClickOutside = (event) => {
  3476.                     if (!dateIcon.contains(event.target) && !dateInput.contains(event.target)) {
  3477.                         dropdown.remove();
  3478.                         document.removeEventListener('click', handleClickOutside);
  3479.                     }
  3480.                 };
  3481.                 document.addEventListener('click', handleClickOutside);
  3482.  
  3483.                 dateInput.addEventListener('change', function () {
  3484.                     const selectedDate = new Date(this.value);
  3485.                     const formatted = selectedDate ?
  3486.                         `${selectedDate.getFullYear()}-${String(selectedDate.getMonth() + 1).padStart(2, '0')}-${String(selectedDate.getDate()).padStart(2, '0')}`
  3487.                         : '';
  3488.  
  3489.                     // Store original icon state
  3490.                     const originalIcon = dateIcon.innerHTML;
  3491.                     const originalWidth = dateIcon.style.width;
  3492.                     const originalMinWidth = dateIcon.style.minWidth;
  3493.  
  3494.                     fetch('/project/update-duedate/', {
  3495.                         method: 'POST',
  3496.                         headers: {
  3497.                             'Content-Type': 'application/json',
  3498.                         },
  3499.                         body: JSON.stringify({
  3500.                             taskId: taskId,
  3501.                             date: formatted
  3502.                         })
  3503.                     })
  3504.                     .then(response => response.json())
  3505.                     .then(data => {
  3506.                         if (data.success) {
  3507.                             const { label, color } = getDateLabelAndColor(formatted);
  3508.                             dateIcon.innerHTML = label;
  3509.                             dateIcon.style.color = color;
  3510.                             dateIcon.style.width = "auto";
  3511.                             dateIcon.style.minWidth = "100px";
  3512.                             dropdown.remove();
  3513.                         } else {
  3514.                             throw new Error('Failed to update due date');
  3515.                         }
  3516.                     })
  3517.                     .catch(error => {
  3518.                         console.error('Error:', error);
  3519.                         // Revert to original state
  3520.                         dateIcon.innerHTML = originalIcon;
  3521.                         dateIcon.style.width = originalWidth;
  3522.                         dateIcon.style.minWidth = originalMinWidth;
  3523.                         alert('Failed to update due date. Please try again.');
  3524.                     });
  3525.                 });
  3526.             }
  3527.            
  3528.             function openBountyDropdown(taskId, bountyIcon)
  3529.                 {
  3530.                     let currentValue = bountyIcon.value || "";
  3531.                     const container = document.createElement('div');
  3532.                     container.classList.add('bounty-container');
  3533.                     container.style.display = 'inline-flex';
  3534.                     container.style.alignItems = 'center';  
  3535.                     container.style.gap = '5px';  
  3536.                     container.style.width = '35px';  
  3537.            
  3538.                     // Create input field if clicking on the current text
  3539.                     const inputField = document.createElement('input');
  3540.                     inputField.type = 'text';
  3541.                     inputField.className = 'bounty-input';
  3542.                     inputField.value = currentValue;  
  3543.                    
  3544.                     inputField.style.textAlign = 'center';
  3545.                     inputField.style.border = '1px solid #ababab';
  3546.                     inputField.style.borderRadius = '4px';
  3547.                     inputField.style.backgroundColor = 'transparent';
  3548.                     inputField.style.width = "35px";
  3549.            
  3550.                     // Append the input field into the container
  3551.                    
  3552.                     container.appendChild(inputField);
  3553.            
  3554.                     // Replace the SVG or text with the container holding the input field
  3555.                     bountyIcon.innerHTML = '';
  3556.                     bountyIcon.appendChild(container);
  3557.            
  3558.                    
  3559.                     inputField.focus();
  3560.                     const value = inputField.value.trim();  // Get the trimmed value
  3561.                         if (value) {
  3562.                             currentValue = value;  // Save the value entered by the user
  3563.                             currentHtml = value;}
  3564.                    
  3565.                     inputField.addEventListener('blur', function () {
  3566.                         const value = inputField.value.trim();  // Get the trimmed value
  3567.            
  3568.                         // If the input is not empty, save the new value
  3569.                         if (value) {
  3570.                             currentValue = value;  // Save the value entered by the user
  3571.                             currentHtml = value;
  3572.                         }
  3573.                         else {
  3574.                             currentValue = 1;
  3575.                             currentHtml = 1;
  3576.                         }
  3577.            
  3578.                        
  3579.                         fetch('/project/update-bounty/', {
  3580.                             method: 'POST',
  3581.                             headers: {
  3582.                                 'Content-Type': 'application/json',
  3583.                             },
  3584.                             body: JSON.stringify({
  3585.                                 taskId: taskId,
  3586.                                 bounty: currentValue
  3587.                             })
  3588.                         })
  3589.                         .then(response => response.json())
  3590.                         .then(data => {
  3591.                             console.log('Priority updated successfully', data);
  3592.                         })
  3593.                         .catch(error => {
  3594.                             console.error('Error updating priority:', error);
  3595.                         });
  3596.                         bountyIcon.innerHTML = currentHtml;
  3597.                     });
  3598.                     inputField.addEventListener('keydown', function(event) {
  3599.                         if (event.key === 'Enter') {
  3600.                             const value = inputField.value.trim();  // Get the trimmed value
  3601.            
  3602.                             // If the input is not empty, save the new value
  3603.                             if (value) {
  3604.                                 currentValue = value;  // Save the value entered by the user
  3605.                                 currentHtml = value;
  3606.                             }
  3607.                             else {
  3608.                                 currentValue = 1;
  3609.                                 currentHtml = 1;
  3610.                             }
  3611.                
  3612.                            
  3613.                             fetch('/project/update-bounty/', {
  3614.                                 method: 'POST',
  3615.                                 headers: {
  3616.                                     'Content-Type': 'application/json',
  3617.                                 },
  3618.                                 body: JSON.stringify({
  3619.                                     taskId: taskId,
  3620.                                     bounty: currentValue
  3621.                                 })
  3622.                             })
  3623.                             .then(response => response.json())
  3624.                             .then(data => {
  3625.                                 console.log('Priority updated successfully', data);
  3626.                             })
  3627.                             .catch(error => {
  3628.                                 console.error('Error updating priority:', error);
  3629.                             });
  3630.  
  3631.                             bountyIcon.innerHTML = currentHtml;
  3632.                        
  3633.                     }
  3634.            
  3635.                     });
  3636.                    
  3637.                 }
  3638.  
  3639.             document.querySelectorAll('.bountie-input').forEach(bounty => {
  3640.  
  3641.                 bounty.addEventListener('click', function(event) {
  3642.                     const userCondition = document.getElementById('user-condition').dataset.userAllowed;
  3643.  
  3644.                         if (userCondition === "true") {
  3645.                             const button = bounty.querySelector('.bounty-btn');
  3646.  
  3647.                             const id = button.id;
  3648.                             openBountyDropdown(id,button);
  3649.                         }
  3650.  
  3651.                 });
  3652.             });
  3653.             let originalOrder = []; // Array to store the original order of rows
  3654.             let sortState = {}; // Store the sort state for each column (og, asc, desc)
  3655.            
  3656.             function storeOriginalOrder(table) {
  3657.                 const rows = Array.from(table.querySelectorAll('tbody tr'));
  3658.                 originalOrder = rows.map(row => row.cloneNode(true)); // Clone rows to preserve original order
  3659.                 console.log(originalOrder)
  3660.             }
  3661.            
  3662.             function restoreOriginalOrder(table) {
  3663.                 const tbody = table.querySelector('tbody');
  3664.                 tbody.innerHTML = '';  // Clear current rows
  3665.                 originalOrder.forEach(row => tbody.appendChild(row));  // Append original rows
  3666.             }
  3667.            
  3668.             function getColumnIndex(column, key) {
  3669.                 const table = document.getElementById(`milestone-${key}`);  // Get the table element dynamically using the key
  3670.                 const headers = Array.from(table.querySelectorAll('th'));
  3671.                 return headers.indexOf(column);  // Get the index of the clicked column
  3672.             }
  3673.            
  3674.             function groupRowsByTaskId(rows) {
  3675.                 const grouped = {};
  3676.                 rows.forEach(row => {
  3677.                     const taskId = row.getAttribute('data-task-id');
  3678.                     if (!grouped[taskId]) {
  3679.                         grouped[taskId] = [];
  3680.                     }
  3681.                     grouped[taskId].push(row);
  3682.                 });
  3683.                 return Object.values(grouped);  // Return an array of grouped rows
  3684.             }
  3685.            
  3686.             function sortTable(column, key) {
  3687.                 const table = document.getElementById(`milestone-${key}`);  // Get the table element dynamically using the key
  3688.                 if (!table) return;  // Exit if the table doesn't exist
  3689.            
  3690.                 // Check if original order is already stored, otherwise store it
  3691.                 if (originalOrder.length === 0) {
  3692.                     storeOriginalOrder(table);
  3693.                 }
  3694.            
  3695.                 const rows = Array.from(table.querySelectorAll('tbody tr'));  // Get all rows in the table body
  3696.                 const filteredRows = rows.filter(row => !row.classList.contains('add-task-rows'));  // Exclude 'add-task-row'
  3697.            
  3698.                 const index = getColumnIndex(column, key);  // Get the column index based on the clicked <th>
  3699.            
  3700.                 // Group rows by task_id (main task and subtasks together)
  3701.                 const groupedRows = groupRowsByTaskId(filteredRows);
  3702.            
  3703.                 // Initialize the sort state for this column if not already initialized
  3704.                 if (!sortState[key]) {
  3705.                     sortState[key] = 'og';  // Default to original (og)
  3706.                 }
  3707.            
  3708.                 // Determine the sort direction based on current state
  3709.                 let direction = sortState[key];
  3710.            
  3711.                 // Sort rows based on the column and direction
  3712.                 groupedRows.sort((groupA, groupB) => {
  3713.                     const cellA = groupA[0].cells[index].textContent.trim();
  3714.                     const cellB = groupB[0].cells[index].textContent.trim();
  3715.            
  3716.                     // If sorting by date, parse the date before comparing
  3717.                     if (column.dataset.sort === 'date' || column.dataset.sort === 'end' || column.dataset.sort === 'due') {
  3718.                         const datecellA = groupA[0].cells[index];
  3719.                         const cellValueA = datecellA.getAttribute('value');
  3720.                        
  3721.                         const datecellB = groupB[0].cells[index];
  3722.                         const cellValueB = datecellB.getAttribute('value');
  3723.                        
  3724.                         // Parse date values, handling null or invalid dates by assigning a minimum placeholder date
  3725.                         const dateA = cellValueA ? new Date(cellValueA) : new Date(0);  // Use Jan 1, 1970 for null/invalid
  3726.                         const dateB = cellValueB ? new Date(cellValueB) : new Date(0);
  3727.                    
  3728.                         // Compare dates, treating nulls/invalids as the lowest values
  3729.                         if (isNaN(dateA) && isNaN(dateB)) return 0;  // Both invalid, treat as equal
  3730.                         if (isNaN(dateA)) return direction === 'asc' ? 1 : -1;  // A is invalid, so it should come first
  3731.                         if (isNaN(dateB)) return direction === 'asc' ? -1 : 1;  // B is invalid, so it should come first
  3732.                        
  3733.                         // Sort normally if both dates are valid
  3734.                         return direction === 'asc' ?  dateB - dateA : dateA - dateB ;
  3735.                     }
  3736.  
  3737.                     if (column.dataset.sort === 'priority') {
  3738.                         const priorityMap = {
  3739.                             urgent: 4,
  3740.                             high: 3,
  3741.                             normal: 2,
  3742.                             low: 1
  3743.                         };
  3744.                    
  3745.                         const priorityA = groupA[0].cells[index].getAttribute('value') || 'low';  // Default to 'low' if null
  3746.                         const priorityB = groupB[0].cells[index].getAttribute('value') || 'low';
  3747.                    
  3748.                         const priorityValueA = priorityMap[priorityA.toLowerCase()] || 0;  // Default to 0 if priority not in map
  3749.                         const priorityValueB = priorityMap[priorityB.toLowerCase()] || 0;
  3750.                    
  3751.                         return direction === 'asc' ?  priorityValueB - priorityValueA : priorityValueA - priorityValueB;
  3752.                     }
  3753.                    
  3754.                    
  3755.                    
  3756.                     const a = column.dataset.sort === 'progress'  ? parseInt(cellA) : cellA.toLowerCase();
  3757.                     const b = column.dataset.sort === 'progress' ? parseInt(cellB) : cellB.toLowerCase();
  3758.  
  3759.                    
  3760.            
  3761.                     return direction === 'asc' ?  (a > b ? -1 : 1) : (a < b ? -1 : 1);
  3762.                 });
  3763.  
  3764.                   if (column.dataset.sort === 'date' || column.dataset.sort === 'end' || column.dataset.sort === 'due') {
  3765.                     groupedRows.forEach(group => {
  3766.                     if (group.length > 1) {
  3767.                         // Separate parent task from subtasks
  3768.                         const parentTask = group[0];
  3769.                         const subtasks = group.slice(1);
  3770.                        
  3771.                         // Sort subtasks by due date
  3772.                         subtasks.sort((rowA, rowB) => {
  3773.                             const datecellA = rowA.cells[index];
  3774.                             const cellValueA = datecellA.getAttribute('value');
  3775.                            
  3776.                             const datecellB = rowB.cells[index];
  3777.                             const cellValueB = datecellB.getAttribute('value');
  3778.                            
  3779.                             const dateA = cellValueA ? new Date(cellValueA) : new Date(0);
  3780.                             const dateB = cellValueB ? new Date(cellValueB) : new Date(0);
  3781.                        
  3782.                             if (isNaN(dateA) && isNaN(dateB)) return 0;
  3783.                             if (isNaN(dateA)) return direction === 'asc' ? 1 : -1;
  3784.                             if (isNaN(dateB)) return direction === 'asc' ? -1 : 1;
  3785.                            
  3786.                             return direction === 'asc' ? dateB - dateA : dateA - dateB;
  3787.                         });
  3788.                        
  3789.                         // Reconstruct the group with parent task first, then sorted subtasks
  3790.                         group.length = 0;
  3791.                         group.push(parentTask, ...subtasks);
  3792.                     }
  3793.                 });
  3794.             }
  3795.            
  3796.                 // Rebuild the table with the sorted rows
  3797.                 const tbody = table.querySelector('tbody');
  3798.                 const addTaskRows = Array.from(table.querySelectorAll('tbody tr.add-task-rows'));
  3799.                 tbody.innerHTML = '';  // Clear existing rows
  3800.            
  3801.                 // Append sorted rows (main tasks and subtasks)
  3802.                 groupedRows.forEach(group => {
  3803.                     group.forEach(row => tbody.appendChild(row));  // Append all rows in the group (main task and subtasks)
  3804.                 });
  3805.            
  3806.                 // Always append 'add-task-row' last
  3807.                 addTaskRows.forEach(row => tbody.appendChild(row));  // Add all 'add-task-row' rows at the bottom
  3808.            
  3809.                 // Toggle the sorting order for the next time
  3810.                 if (direction === 'og') {
  3811.                     sortState[key] = 'asc';  // If it's original, next will be ascending
  3812.                 } else if (direction === 'asc') {
  3813.                     sortState[key] = 'desc';  // If it was ascending, next will be descending
  3814.                 } else {
  3815.                     sortState[key] = 'og';  // If it was descending, next will be original
  3816.                     restoreOriginalOrder(table);  // Restore original (custom) order
  3817.                 }
  3818.            
  3819.                
  3820.                 // Add the appropriate class and icon for the clicked column
  3821.                 const icon = column.querySelector('.sort-icon');
  3822.                 icon.classList.remove('fa-sort-up', 'fa-sort-down', 'fa-sort');
  3823.                 if (sortState[key] === 'asc') {
  3824.                     column.classList.add('sorted-asc');
  3825.                     icon.classList.add('fa-sort-down');
  3826.  
  3827.                     icon.title = "Ascending";
  3828.                 } else if (sortState[key] === 'desc') {
  3829.                     column.classList.add('sorted-desc');
  3830.                     icon.classList.add('fa-sort-up');
  3831.                     icon.title = "Descending";
  3832.                 } else {
  3833.                     column.classList.add('sorted-original');
  3834.                     icon.classList.add('fa-sort');
  3835.                     icon.title = "Custom Order";
  3836.                 }
  3837.             }
  3838.            
  3839.             function updateProgress(taskRow, alltask=false) {
  3840.                 let subtaskRow = taskRow.nextElementSibling; // Start checking from the next row
  3841.                 let totalSubtasks = 0;
  3842.                 let remainingSubtasks = 0;
  3843.            
  3844.                 // Get the task ID from the task row to ensure uniqueness
  3845.                 const taskId = taskRow.id;
  3846.                
  3847.                 // Traverse until we hit the next task row
  3848.                 while (subtaskRow && !subtaskRow.classList.contains('task-row') && !subtaskRow.classList.contains('task-row-checkpoint'))   {
  3849.                     if (subtaskRow.classList.contains('subtask-row') && !subtaskRow.classList.contains('mark-as-complete')) {
  3850.                         totalSubtasks++;
  3851.                         const checkbox = subtaskRow.querySelector('input[type="checkbox"]');
  3852.                         if (!checkbox.checked) {
  3853.                             remainingSubtasks++;
  3854.                         }
  3855.                     }
  3856.                     subtaskRow = subtaskRow.nextElementSibling; // Move to the next row
  3857.                 }
  3858.            
  3859.                 // Get the progress element for the current task and update it
  3860.                 const progressElement = taskRow.querySelector('.progress-text');
  3861.                 if (progressElement) {
  3862.                     progressElement.textContent = `${remainingSubtasks}`;
  3863.                 }
  3864.            
  3865.                 const completedSubtasks = totalSubtasks - remainingSubtasks;
  3866.                 let completionPercentage = totalSubtasks > 0 ? (completedSubtasks / totalSubtasks) * 100 : 0;
  3867.            
  3868.                 const statusBar = taskRow.querySelector('.status-bar-container');
  3869.                 const statusLength = taskRow.querySelector('.status-bar-completed');
  3870.                 const tooltip = taskRow.querySelector('.progress-tooltip');
  3871.                 const noSubtasksMessage = taskRow.querySelector('.no-subtasks-message');
  3872.            
  3873.                 if (totalSubtasks === 0) {
  3874.                     if (statusBar) {
  3875.                         statusBar.style.display = "none";
  3876.                     }
  3877.                     if (tooltip) {
  3878.                         tooltip.textContent = '';
  3879.                     }
  3880.                     if (noSubtasksMessage) {
  3881.                         noSubtasksMessage.style.display = 'block';
  3882.                     }
  3883.                 } else {
  3884.                     if (noSubtasksMessage) {
  3885.                         noSubtasksMessage.style.display = 'none'; // Hide "No Subtasks" message
  3886.                     }
  3887.            
  3888.                     if (statusBar) {
  3889.                         statusBar.style.display = "block";
  3890.                         statusLength.style.width = `${completionPercentage}%`;
  3891.                     }
  3892.            
  3893.                     if (tooltip) {
  3894.                         tooltip.textContent = `${remainingSubtasks} out of ${totalSubtasks} tasks remaining`;
  3895.                     }
  3896.                 }
  3897.  
  3898.                 if(remainingSubtasks == 0 && totalSubtasks > 0 && !alltask){
  3899.                     document.getElementById(`${taskRow.getAttribute("data-task-id")}`).setAttribute('hidden', 'true');
  3900.                     document.getElementById(`${taskRow.getAttribute("data-task-id")}`).setAttribute('value', 'C');
  3901.                 }
  3902.            
  3903.                 return completionPercentage;
  3904.             }
  3905.            
  3906.            
  3907.  
  3908.             function updateAllStatusBars(completionPercentages) {
  3909.                 const statusBars = document.querySelectorAll('.status-bar-completed');
  3910.  
  3911.                 statusBars.forEach((bar, index) => {
  3912.                     const percentage = completionPercentages[index] || 0;
  3913.                     bar.style.width = percentage + '%';
  3914.                 });
  3915.             }
  3916.             document.addEventListener('change', function(event) {
  3917.                 if (event.target.matches('.subtask-row input[type="checkbox"]')) {
  3918.                     let thisRow = event.target.closest('tr');
  3919.                     let taskRow = thisRow.previousElementSibling;
  3920.                     while (taskRow && !taskRow.classList.contains('task-row')) {
  3921.                         taskRow = taskRow.previousElementSibling;
  3922.                     }
  3923.                     updateProgress(taskRow);
  3924.                 }
  3925.             });
  3926.  
  3927.  
  3928.        
  3929.         document.querySelectorAll('.add-task-rows').forEach(subtaskRow => {
  3930.             subtaskRow.addEventListener('click', function(event) {
  3931.                     if (rowIsOpen == false){
  3932.                         const button = subtaskRow.querySelector('.add-task-btn');
  3933.                         addTaskRow(button);
  3934.                         rowIsOpen = true;
  3935.                     }
  3936.                    
  3937.  
  3938.             });
  3939.         });
  3940.        
  3941.         const dropdown = document.getElementById('taskDropdown');
  3942.         const tableRows = document.querySelectorAll('#task-table-body tr');
  3943.  
  3944.         // Update the dropdown change handler
  3945.         dropdown.addEventListener('change', function() {
  3946.             const filterValue = this.value;
  3947.             filtered = filterValue;
  3948.  
  3949.             // Get all tasks and subtasks
  3950.             const allTasks = document.querySelectorAll('.task-row, .subtask-row, .task-row-checkpoint');
  3951.            
  3952.             allTasks.forEach(row => {
  3953.                 // Skip special rows
  3954.                 if (row.classList.contains('add-task-rows') ||
  3955.                     row.classList.contains('add-task-row') ||
  3956.                     row.classList.contains('mark-complete')) {
  3957.                     return;
  3958.                 }
  3959.  
  3960.                 const taskStatus = row.getAttribute('value');
  3961.                 const isSubtask = row.classList.contains('subtask-row');
  3962.                 const parentTaskId = row.getAttribute('data-task-id');
  3963.  
  3964.                 if (filterValue === 'all') {
  3965.                     // Remove hidden attribute regardless of status
  3966.                     row.removeAttribute('hidden');
  3967.                    
  3968.                     // For parent tasks, handle subtask visibility
  3969.                     if (!isSubtask) {
  3970.                         const subtasks = document.querySelectorAll(`.subtask-row[data-task-id="${row.id}"]`);
  3971.                         subtasks.forEach(subtask => {
  3972.                             if (row.dataset.open === "true") {
  3973.                                 subtask.removeAttribute('hidden');
  3974.                             } else {
  3975.                                 subtask.style.display = 'none';
  3976.                             }
  3977.                         });
  3978.                     }
  3979.                 } else if (filterValue === 'pending') {
  3980.                     if (taskStatus === 'C') {
  3981.                         row.setAttribute('hidden', 'true');
  3982.                     } else {
  3983.                         row.removeAttribute('hidden');
  3984.                        
  3985.                         // For parent tasks, ensure subtasks follow the same rule
  3986.                         if (!isSubtask) {
  3987.                             const subtasks = document.querySelectorAll(`.subtask-row[data-task-id="${row.id}"]`);
  3988.                             subtasks.forEach(subtask => {
  3989.                                 if (subtask.getAttribute('value') === 'C') {
  3990.                                     subtask.setAttribute('hidden', 'true');
  3991.                                 } else if (row.dataset.open === "true") {
  3992.                                     subtask.removeAttribute('hidden');
  3993.                                 }
  3994.                             });
  3995.                         }
  3996.                     }
  3997.                 }
  3998.             });
  3999.  
  4000.             // Update progress for all parent tasks
  4001.             document.querySelectorAll('.task-row').forEach(row => {
  4002.                 if (!row.classList.contains('subtask-row')) {
  4003.                     updateProgress(row, true);
  4004.                 }
  4005.             });
  4006.         });
  4007.  
  4008.  
  4009.         function toggleSubtask(svgElement) {
  4010.            
  4011.             const taskRow = svgElement.closest('tr');
  4012.             const milestoneSection = svgElement.closest('table');
  4013.            
  4014.             const milestoneHeader = milestoneSection.querySelector('th');
  4015.  
  4016.             const milestoneName = milestoneHeader.textContent.trim();
  4017.             const arrowSvg = taskRow.querySelector('.arrow-svg');
  4018.             const taskName = taskRow.querySelector('.task-name').textContent.trim();
  4019.             const taskId = taskRow.id;
  4020.            
  4021.            
  4022.            
  4023.             // generate a unique class name
  4024.             const taskIdentifier = `subtask-${taskName.replace(/\s+/g, '-').toLowerCase()}-milestoneName`;
  4025.            
  4026.             // add unique classname
  4027.             let nextRow = taskRow.nextElementSibling;
  4028.             while (nextRow && nextRow.classList.contains('subtask-row')) {
  4029.                 nextRow.classList.add(`subtask-${taskId}`);
  4030.                 nextRow = nextRow.nextElementSibling;
  4031.             }
  4032.            
  4033.             // select all subtasks
  4034.             const subtasks = document.querySelectorAll(`.subtask-${taskId}`);
  4035.            
  4036.             // toggle the display of the subtask rows
  4037.             subtasks.forEach(row => {
  4038.                
  4039.                 if (row.style.display === "none"){
  4040.                     if (arrowSvg) {
  4041.                    
  4042.                         arrowSvg.classList.add('rotated');
  4043.                     }
  4044.                     taskRow.dataset.open = "true";
  4045.                 }
  4046.                 else{
  4047.                     if (arrowSvg) {
  4048.                    
  4049.                         arrowSvg.classList.remove('rotated');
  4050.                     }
  4051.                     taskRow.dataset.open = "false";
  4052.                 }
  4053.                 row.style.display = (row.style.display === 'none' || row.style.display === '') ? 'table-row' : 'none';
  4054.                
  4055.             });
  4056.         }
  4057.         function toggleTaskCompletion(taskId, button) {
  4058.             const taskRow = button.closest('.task-row');
  4059.             const isCompleted = taskRow.getAttribute('value') =="C";
  4060.             const newStatus = isCompleted ? 'I' : 'C';
  4061.             taskRow.setAttribute('value',newStatus);
  4062.        
  4063.             updateTaskStatus(taskId, newStatus);
  4064.            
  4065.             const parentRow = taskRow.parentElement;
  4066.             const subtasks = parentRow.querySelectorAll('.subtask-row');
  4067.             if ( newStatus == 'C'){
  4068.             subtasks.forEach(subtaskRow => {
  4069.                     if ( !subtaskRow.getAttribute('hidden') == true){
  4070.                         if (subtaskRow.classList.contains('subtask-row')  && !subtaskRow.classList.contains('add-subtask-row')) {
  4071.                             const subtaskId = subtaskRow.getAttribute('data-subtask-id');
  4072.                             const checkbox = subtaskRow.querySelector('input[type="checkbox"]');
  4073.                             checkbox.checked = checkbox.checked ? false : true;
  4074.                             if (subtaskId && subtaskId != "") {
  4075.                                 updateTaskStatus(subtaskId, newStatus);
  4076.                             }
  4077.                         }
  4078.                     }
  4079.                 }
  4080.             );}
  4081.            
  4082.            
  4083.             if (isCompleted) {
  4084.                 button.innerText = "Mark as Complete";
  4085.             } else {
  4086.                 // If the task was incomplete, show the main task row
  4087.                
  4088.                 taskRow.setAttribute('hidden', true);
  4089.                 let nextRow = taskRow.nextElementSibling;
  4090.                
  4091.                     while (nextRow) {
  4092.                         if (nextRow.classList.contains('task-row') || nextRow.classList.contains('add-task-row') || nextRow.classList.contains('task-row-checkpoint'))  {
  4093.                             break; // Stop hiding/showing when we hit the next task row or add task row
  4094.                         }
  4095.                         nextRow.hidden = true; // Toggle the visibility of the following rows
  4096.                         nextRow = nextRow.nextElementSibling; // Move to the next row
  4097.                     }
  4098.                 button.innerText = "Mark as Incomplete"; // Change button text to "Mark as Incomplete"
  4099.             }
  4100.        
  4101.             // Update the onclick handler
  4102.             button.setAttribute('onclick', `toggleTaskCompletion(${taskId}, this)`); // Change the click handler to the same function
  4103.         }
  4104.        
  4105.         // Function to update task status
  4106.         function updateTaskStatus(taskId, checkbox) {
  4107.             const isChecked = checkbox.checked;
  4108.             const newStatus = isChecked ? 'C' : 'I';
  4109.             const taskRow = checkbox.closest('tr');
  4110.            
  4111.             // Store references to related elements
  4112.             const parentTaskId = taskRow.getAttribute('data-task-id');
  4113.             const isSubtask = taskRow.classList.contains('subtask-row');
  4114.             let parentRow = null;
  4115.            
  4116.             if (isSubtask) {
  4117.                 parentRow = document.getElementById(parentTaskId);
  4118.             }
  4119.  
  4120.             fetch(`/project/update-subtask-status/${taskId}/`, {
  4121.                 method: 'POST',
  4122.                 headers: {
  4123.                     'Content-Type': 'application/json',
  4124.                 },
  4125.                 body: JSON.stringify({ status: newStatus })
  4126.             })
  4127.             .then(response => {
  4128.                 if (!response.ok) {
  4129.                     throw new Error('Failed to update task status.');
  4130.                 }
  4131.                 return response.json();
  4132.             })
  4133.             .then(data => {
  4134.                 // Update task's status attributes
  4135.                 taskRow.setAttribute('data-status', newStatus);
  4136.                 taskRow.setAttribute('value', newStatus);
  4137.                
  4138.                 if (filtered === "pending") {
  4139.                     if (isChecked) {
  4140.                         taskRow.setAttribute('hidden', 'true');
  4141.                        
  4142.                         // If it's a subtask, handle parent task visibility
  4143.                         if (isSubtask && parentRow) {
  4144.                             let allSubtasksComplete = true;
  4145.                             const siblingSubtasks = document.querySelectorAll(`.subtask-row[data-task-id="${parentTaskId}"]`);
  4146.                             siblingSubtasks.forEach(subtask => {
  4147.                                 if (subtask.getAttribute('value') !== 'C') {
  4148.                                     allSubtasksComplete = false;
  4149.                                 }
  4150.                             });
  4151.                            
  4152.                             if (allSubtasksComplete) {
  4153.                                 parentRow.setAttribute('hidden', 'true');
  4154.                             }
  4155.                         }
  4156.                     }
  4157.                 } else if (filtered === "all") {
  4158.                     // In "all" view, never hide the task
  4159.                     taskRow.removeAttribute('hidden');
  4160.                    
  4161.                     // If it's a parent task, ensure subtasks visibility is maintained
  4162.                     if (!isSubtask) {
  4163.                         const subtasks = document.querySelectorAll(`.subtask-row[data-task-id="${taskId}"]`);
  4164.                         subtasks.forEach(subtask => {
  4165.                             if (taskRow.dataset.open === "true") {
  4166.                                 subtask.removeAttribute('hidden');
  4167.                             }
  4168.                         });
  4169.                     }
  4170.                 }
  4171.  
  4172.                 // Update progress indicators
  4173.                 const progressBar = taskRow.querySelector('.status-bar-completed');
  4174.                 if (progressBar) {
  4175.                     progressBar.style.width = isChecked ? '100%' : '0%';
  4176.                 }
  4177.  
  4178.                 const tooltip = taskRow.querySelector('.progress-tooltip');
  4179.                 if (tooltip) {
  4180.                     tooltip.textContent = isChecked ? 'Task completed' : 'Task pending';
  4181.                 }
  4182.  
  4183.                 // Update parent task progress if this is a subtask
  4184.                 if (isSubtask && parentRow) {
  4185.                     updateProgress(parentRow);
  4186.                 }
  4187.             })
  4188.             .catch(error => {
  4189.                 console.error('Error updating task status:', error);
  4190.                 checkbox.checked = !isChecked;
  4191.                 alert('Failed to update task status. Please try again.');
  4192.             });
  4193.         }
  4194.        
  4195.         function updateSubtaskStatus(subtaskId, checkBox) {
  4196.             if (!checkBox) return;
  4197.            
  4198.             checkBox.checked = !checkBox.checked; // Revert the automatic change
  4199.             const newStatus = !checkBox.checked ? 'C' : 'I';
  4200.             const parentRow = checkBox.parentElement.parentElement.parentElement.parentElement;
  4201.            
  4202.             fetch(`/project/update-subtask-status/${subtaskId}/`, {
  4203.                 method: 'POST',
  4204.                 headers: {
  4205.                     'Content-Type': 'application/json',
  4206.                 },
  4207.                 body: JSON.stringify({ status: newStatus })
  4208.             })
  4209.             .then(response => {
  4210.                 if (!response.ok) {
  4211.                     throw new Error('Failed to update subtask status.');
  4212.                 }
  4213.                 checkBox.checked = !checkBox.checked;
  4214.                 if (newStatus == "C" && filtered=="pending"){
  4215.                     parentRow.setAttribute('hidden', true);
  4216.                 }
  4217.                 parentRow.setAttribute('data-status', newStatus);
  4218.                 return response.json();
  4219.             })
  4220.             .then(data => {
  4221.                 console.log('Subtask status updated successfully:', data);
  4222.             })
  4223.             .catch(error => {
  4224.                 console.error('Error updating subtask status:', error);
  4225.             });
  4226.         }
  4227.  
  4228.         function formatDueDate(dateValue){
  4229.             const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  4230.             const day = String(dateValue.getDate()).padStart(2, '0');  // Ensures day is 2 digits, e.g., 01, 02
  4231.             const month = monthNames[dateValue.getMonth()];  // Get the month abbreviation
  4232.             const year = dateValue.getFullYear();  // Get the full year
  4233.  
  4234.             // Combine to form the formatted date
  4235.             const formattedDate = `${day} ${month} ${year}`;
  4236.             return formattedDate;
  4237.         }
  4238.  
  4239.         function getDateLabelAndColor(dueDate) {
  4240.             const today = new Date();
  4241.             const yesterday = new Date(today);
  4242.             yesterday.setDate(today.getDate() - 1);
  4243.             const tomorrow = new Date(today);
  4244.             tomorrow.setDate(today.getDate() + 1);
  4245.        
  4246.             const dueDateObj = new Date(dueDate);
  4247.            
  4248.             // Check if the due date is yesterday, today, or tomorrow
  4249.             if (dueDateObj.toDateString() === yesterday.toDateString()) {
  4250.                 return { label: "Yesterday", color: "red" };
  4251.             } else if (dueDateObj.toDateString() === today.toDateString()) {
  4252.                 return { label: "Today", color: "orange" };
  4253.             } else if (dueDateObj.toDateString() === tomorrow.toDateString()) {
  4254.                 return { label: "Tomorrow", color: "blue" };
  4255.             } else if (dueDateObj < today) {
  4256.                 return { label: formatDueDate(dueDateObj), color: "red" };  // Overdue
  4257.             } else {
  4258.                 return { label: formatDueDate(dueDateObj), color: "black" };  // Future date
  4259.             }
  4260.         }
  4261.  
  4262.         let draggedTask = null;
  4263.         let draggedSubtasks = [];
  4264.         let isSubtaskDragged = false;
  4265.        
  4266.         // Function to capture the dragged task and subtasks (if any)
  4267.         function drag(event) {
  4268.             resetDragState();
  4269.             // console.log("hi");
  4270.             draggedTask = event.target;
  4271.             draggedSubtasks = getSubtasks(draggedTask);
  4272.             isSubtaskDragged = draggedTask.classList.contains('subtask-row');
  4273.             draggedTask.classList.add('dragging');
  4274.             draggedSubtasks.forEach(subtask => subtask.classList.add('dragging'));
  4275.             // console.log(draggedTask)
  4276.         }
  4277.        
  4278.         // Highlight only the current target task
  4279.         function allowDrop(event) {
  4280.             event.preventDefault();
  4281.             const targetRow = event.target.closest('.task-row, .subtask-row, .task-row-checkpoint');
  4282.             removeHighlightFromRows();
  4283.        
  4284.             if (targetRow && targetRow !== draggedTask) {
  4285.                 targetRow.classList.add('highlight');
  4286.             }
  4287.         }
  4288.        
  4289.         // Handle drop event to reassign subtask if necessary
  4290.         function drop(event) {
  4291.             event.preventDefault();
  4292.             const targetRow = event.target.closest('.task-row, .subtask-row, .task-row-checkpoint');
  4293.        
  4294.             if (targetRow && targetRow !== draggedTask) {
  4295.                 if (isSubtaskDragged && targetRow.classList.contains('task-row') && !targetRow.classList.contains('subtask-row') && targetRow.id !== draggedTask.dataset.taskId) {
  4296.                     oldtaskid = draggedTask.dataset.taskId;
  4297.                     moveSubtaskToNewParent(draggedTask, targetRow);
  4298.                     try{
  4299.                     const toggleSvg = targetRow.querySelector('#togglesvg');
  4300.                     const toggleSpan = targetRow.querySelector('#togglespan');
  4301.                    
  4302.                     if (toggleSvg){
  4303.                         if (toggleSvg.style.display == "none"){
  4304.                             toggleSvg.classList.add('rotated');
  4305.                         }
  4306.                         toggleSvg.style.display = "flex";
  4307.                         toggleSpan.style.display = "none";
  4308.                     }
  4309.                     const subtaskCountSpan = targetRow.querySelector('.subtask-count');
  4310.                     let currentCount = parseInt(subtaskCountSpan.textContent.replace(/\D/g, '')) || 0;
  4311.                     currentCount++;
  4312.                     subtaskCountSpan.textContent = `(${currentCount})`;
  4313.  
  4314.                     const parentrow = document.getElementById(oldtaskid);
  4315.  
  4316.                     const subtaskspan = parentrow.querySelector('.subtask-count');
  4317.                     let currentCount2 = parseInt(subtaskspan.textContent.replace(/\D/g, '')) || 0;
  4318.                     currentCount2--;
  4319.                     subtaskspan.textContent = `(${currentCount2})`;
  4320.                 }
  4321.                 catch (error) {
  4322.                     console.log(error);
  4323.                 }
  4324.  
  4325.                 }
  4326.                 else if (targetRow.classList.contains('subtask-row')){
  4327.                     taskId = targetRow.dataset.taskId;
  4328.                     row = document.getElementById(`${taskId}`);
  4329.                     if (row.id !== draggedTask.dataset.taskId){
  4330.                         moveSubtaskToNewParent(draggedTask,row)
  4331.                     }
  4332.                     else{
  4333.                         moveTaskWithSubtasks(draggedTask, targetRow);
  4334.                     updateOrderAfterDrop(draggedTask, targetRow);
  4335.                     }
  4336.                 }
  4337.                 else {
  4338.                     moveTaskWithSubtasks(draggedTask, targetRow);
  4339.                     updateOrderAfterDrop(draggedTask, targetRow);
  4340.                 }
  4341.                
  4342.             }
  4343.             resetDragState();
  4344.         }
  4345.        
  4346.         // Move the subtask under a new parent task in the UI and update parent ID
  4347.         function moveSubtaskToNewParent(subtask, newParentTask) {
  4348.             const allRows = Array.from(document.querySelectorAll('.task-row, .subtask-row'));
  4349.             const newParentIndex = allRows.indexOf(newParentTask);
  4350.        
  4351.             // Place the subtask immediately below the new parent task
  4352.             newParentTask.after(subtask);
  4353.             subtask.dataset.taskId = newParentTask.id;
  4354.             // Update backend with the new parent ID
  4355.             updateSubtaskParentInBackend(subtask.id, newParentTask.id);
  4356.         }
  4357.        
  4358.         // AJAX request to update subtask's parent ID in the backend
  4359.         async function updateSubtaskParentInBackend(subtaskId, newParentId) {
  4360.             try {
  4361.                 const response = await fetch('/project/update-subtask-parent/', {
  4362.                     method: 'POST',
  4363.                     headers: {
  4364.                         'Content-Type': 'application/json',
  4365.                        
  4366.                     },
  4367.                     body: JSON.stringify({
  4368.                         subtask_id: subtaskId,
  4369.                         new_parent_id: newParentId
  4370.                     })
  4371.                 });
  4372.                 if (!response.ok) throw new Error('Failed to update subtask parent');
  4373.             } catch (error) {
  4374.                 console.error(error);
  4375.             }
  4376.         }
  4377.        
  4378.         // Move the main task and its subtasks as a group
  4379.         function moveTaskWithSubtasks(draggedTask, targetRow) {
  4380.             const allRows = Array.from(document.querySelectorAll('.task-row, .subtask-row, .task-row-checkpoint'));
  4381.             const targetIndex = allRows.indexOf(targetRow);
  4382.             const draggedIndex = allRows.indexOf(draggedTask);
  4383.        
  4384.             if (draggedIndex > targetIndex) {
  4385.                 targetRow.before(draggedTask);
  4386.                 draggedSubtasks.forEach(subtask => targetRow.before(subtask));
  4387.             } else {
  4388.                 targetRow.after(draggedTask);
  4389.                 draggedSubtasks.forEach(subtask => draggedTask.after(subtask));
  4390.             }
  4391.         }
  4392.        
  4393.         // Get all subtasks for a given main task
  4394.         function getSubtasks(task) {
  4395.             const taskId = task.id;
  4396.             return Array.from(document.querySelectorAll(`.subtask-row[data-task-id="${taskId}"]`));
  4397.         }
  4398.        
  4399.         // Remove all highlight effects
  4400.         function removeHighlightFromRows() {
  4401.             document.querySelectorAll('.highlight').forEach(row => row.classList.remove('highlight'));
  4402.         }
  4403.        
  4404.         // Reset the drag state
  4405.         function resetDragState() {
  4406.             if (draggedTask) {
  4407.                 draggedTask.classList.remove('dragging');
  4408.                 draggedSubtasks.forEach(subtask => subtask.classList.remove('dragging'));
  4409.                 removeHighlightFromRows();
  4410.             }
  4411.             draggedTask = null;
  4412.             draggedSubtasks = [];
  4413.             isSubtaskDragged = false;
  4414.         }
  4415.        
  4416.         // Update the task order on the backend after drop
  4417.         async function updateOrderAfterDrop(draggedTask, targetRow) {
  4418.             const draggedTaskId = draggedTask.id;
  4419.             const targetTaskId = targetRow.id;
  4420.        
  4421.             try {
  4422.                 const response = await fetch('/project/update-task-order/', {
  4423.                     method: 'POST',
  4424.                     headers: {
  4425.                         'Content-Type': 'application/json',
  4426.                        
  4427.                     },
  4428.                     body: JSON.stringify({
  4429.                         dragged_task_id: draggedTaskId,
  4430.                         target_task_id: targetTaskId
  4431.                     })
  4432.                 });
  4433.                 if (!response.ok) throw new Error('Failed to update task order');
  4434.             } catch (error) {
  4435.                 console.error(error);
  4436.             }
  4437.         }
  4438.        
  4439.        
  4440.  
  4441.        
  4442.         async function saveTaskToBackend(task) {
  4443.             try {
  4444.                 const response = await fetch('/project/add_task/', {
  4445.                     method: 'POST',
  4446.                     headers: {
  4447.                         'Content-Type': 'application/json'
  4448.                     },
  4449.                     body: JSON.stringify(task)
  4450.                 });
  4451.        
  4452.                 if (!response.ok) {
  4453.                     throw new Error('Failed to save task');
  4454.                 }
  4455.        
  4456.                 const result = await response.json();
  4457.                 return result.task_id;
  4458.             } catch (error) {
  4459.                 console.error('Error saving task:', error);
  4460.                 alert('Failed to save task. Please try again.');
  4461.                 return null;
  4462.             }
  4463.         }
  4464.            
  4465.            //function to add subtask
  4466.            async function addSubtask(buttonElement,data,handleKeydown,row) {
  4467.             const milestoneSection = buttonElement.closest('table');
  4468.             const milestoneHeader = milestoneSection.querySelector('thead tr th:first-child');
  4469.             const milestoneText = milestoneHeader ? milestoneHeader.textContent.trim() : null;
  4470.            
  4471.             const milestoneSectionInput = buttonElement.closest('tr');
  4472.             const inputRow = buttonElement.closest('tr')
  4473.             const taskName = buttonElement.dataset.subtask;
  4474.             // we are selecting the inputs from the correct row
  4475.             const subtaskInput =  data.name;
  4476.             const assigneeInput = data.member.id;
  4477.             const dateInput = data.date;
  4478.             const bountieInput = data.bounty;
  4479.             const selectedAssignee = data.member.name;
  4480.             const priorityText = data.priority;
  4481.             let taskRow = inputRow.previousElementSibling;
  4482.            
  4483.             taskRow = inputRow;
  4484.             let { label, color } = { label: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  4485.                 <g id="SVGRepo_iconCarrier">
  4486.                     <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  4487.                 </g>
  4488.             </svg>`, color: "black" }; // Initialize with default values
  4489.             if (dateInput) {
  4490.                 const formatted = `${dateInput.getFullYear()}-${String(dateInput.getMonth() + 1).padStart(2, '0')}-${String(dateInput.getDate()).padStart(2, '0')}`;
  4491.                 ({ label, color } = getDateLabelAndColor(formatted));
  4492.             }
  4493.  
  4494.             const toggleSvg = taskRow.querySelector('#togglesvg');
  4495.             const toggleSpan = taskRow.querySelector('#togglespan');
  4496.             if (toggleSvg){
  4497.                 if (toggleSvg.style.display == "none"){
  4498.                     toggleSvg.classList.add('rotated');
  4499.                 }
  4500.                 toggleSvg.style.display = "flex";
  4501.                 toggleSpan.style.display = "none";
  4502.             }
  4503.            
  4504.             // validate the task name input
  4505.             if (!subtaskInput.trim()) {
  4506.                 alert("Please enter a valid task name.");
  4507.                 return;
  4508.             }
  4509.  
  4510.             let formattedDate = null;
  4511.             if (dateInput){
  4512.                 duedate = dateInput;
  4513.                 formattedDate = `${duedate.getFullYear()}-${String(duedate.getMonth() + 1).padStart(2, '0')}-${String(duedate.getDate()).padStart(2, '0')}`;
  4514.             }
  4515.             else{
  4516.                 formattedDate = null;
  4517.                 duedate = null;
  4518.             }
  4519.            
  4520.             if (subtaskInput.trim() === "") {
  4521.                 alert("Please enter a subtask.");
  4522.                 return;
  4523.             }
  4524.  
  4525.             if (dateInput.value){
  4526.                 duedate = dateInput.value;
  4527.             }
  4528.             else{
  4529.                 duedate = null;
  4530.             }
  4531.             let priorityIcon = "";
  4532.             if (priorityText){
  4533.                 priorityIcon = priorityMapping[priorityText.toLowerCase()].icon;
  4534.             }
  4535.             else{
  4536.                 priorityIcon = priorityMapping['normal'].icon;
  4537.             }
  4538.             //BACKEND Call
  4539.             const taskData = {
  4540.                 name: subtaskInput,
  4541.                 assignee: assigneeInput,
  4542.                 dueDate: duedate,
  4543.                 bounty: bountieInput,
  4544.                 parentId : data.parent,
  4545.                 project_ID: projectId,
  4546.                 milestone: milestoneText
  4547.             };
  4548.  
  4549.            
  4550.             const taskId = await saveTaskToBackend(taskData);
  4551.  
  4552.             // create a new tr  for the subtask
  4553.             const newRow = document.createElement('tr');
  4554.             newRow.classList.add("subtask-row");
  4555.             newRow.style.display="table-row"
  4556.             newRow.style.textAlign = 'left';
  4557.             newRow.style.height = '40px';
  4558.             newRow.id = taskId;
  4559.             newRow.setAttribute('draggable', 'true');
  4560.             newRow.setAttribute('ondragstart', 'drag(event)');
  4561.             newRow.setAttribute('ondragover', 'allowDrop(event)');
  4562.             newRow.setAttribute('ondrop', 'drop(event)');
  4563.             newRow.setAttribute('data-text-id',data.parent);
  4564.            
  4565.  
  4566.  
  4567.             // ineerhtml
  4568.             newRow.innerHTML = `
  4569.                                            
  4570.  
  4571.                 <td class="sub-task-elem" style="padding: 16px 32px;  display:flex; flex-direction:row; justify-content: space-between; align-items: center;">
  4572.                     <div style="display: flex; flex-direction: row; align-items: center; gap: 4px;">
  4573.  
  4574.                     <label class="circular-checkbox"> <input class="taskCheckbox" onchange="updateSubtaskStatus(${taskId}, this)"
  4575.                         type="checkbox" name=""> </label>
  4576.                     <span onclick="openTaskModal(${taskId})" class="task-name" id="task-name-${taskId}"> ${subtaskInput}</span> </div>
  4577.                      <div style="display: flex; gap: 10px;">
  4578.                                        
  4579.                                         <!-- Edit Icon to Rename Task -->
  4580.                                         <button title="Rename Task" onclick="editTask(${taskId})" class="edit-btn">
  4581.                                             <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
  4582.                                                 <path d="M7.37333 4.01333L7.98667 4.62667L1.94667 10.6667H1.33333V10.0533L7.37333 4.01333ZM9.77333 0C9.60667 0 9.43333 0.0666666 9.30667 0.193333L8.08667 1.41333L10.5867 3.91333L11.8067 2.69333C12.0667 2.43333 12.0667 2.01333 11.8067 1.75333L10.2467 0.193333C10.1133 0.06 9.94667 0 9.77333 0ZM7.37333 2.12667L0 9.5V12H2.5L9.87333 4.62667L7.37333 2.12667Z" fill="#939CA3"/>
  4583.                                                 </svg>
  4584.                                                
  4585.                                         </button>
  4586.                                         <button title="Delete Task" onclick="deleteTask(this,${taskId})" class="edit-btn">
  4587.                                             <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  4588.                                                     <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  4589.                                                 </svg>
  4590.  
  4591.                                         </button>
  4592.                                     </div>
  4593.                 </td>
  4594.                 <td style="border-left: 1px solid #CED4DA; padding-left: 10px;"></td>
  4595.                     <td class="assignee-input" style="border-left: 1px solid #CED4DA; padding-left: 10px; display: flex; justify-content: center; align-items: center;">
  4596.                         <button title="Assign Assignee" id="${taskId}" class="assign-btn" onclick="openAssigneeDropdown(${taskId},this)" style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  4597.                             ${selectedAssignee ? `
  4598.                                 <div class="initials-circle" style="width: 25px; height: 25px; border-radius: 50%; display: flex; justify-content: center; align-items: center; background-color: #7c4dff; color: #fff; font-size: 14px; cursor: pointer;">
  4599.                                     ${getInitials(selectedAssignee)}
  4600.                                 </div>` : `
  4601.                                     <svg class="assignee-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="width: 24px; height: 24px; fill: #ABABAB;">
  4602.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  4603.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  4604.                                                     <g id="SVGRepo_iconCarrier">
  4605.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" />
  4606.                                                     </g>
  4607.                                                 </svg>`
  4608.                             }
  4609.                         </button>
  4610.                     </td>
  4611.  
  4612.                 <td class="date-input" value="${duedate}" style=" justify-items:center; align-items: center; border-left: 1px solid #CED4DA; padding-left: 10px; color: ${color};">
  4613.                     <button title="Change Date" class="assign-btn"
  4614.                     {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  4615.                     onclick="openDueDateDropdown(${taskId},this)"
  4616.                     {% endif %}
  4617.                     style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  4618.  
  4619.                         ${label}
  4620.                     </button>
  4621.                     </td>
  4622.                 <td class="priority-input" value="${priorityText}" title="${priorityText}"  style="border-left: 1px solid #CED4DA; padding-left: 10px; text-align: center; vertical-align: middle;justify-content: center; display:flex;">
  4623.                                         <button title="Change Priority" class="assign-btn"
  4624.                                        
  4625.                                         onclick="openPriorityDropdown(${taskId},this)"
  4626.                                        
  4627.                                         style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  4628.  
  4629.                                         ${priorityIcon || '-' }
  4630.                                         </button>
  4631.                                     </td>
  4632.                 <td class="bountie-input" style="padding-left: 10px; justify-content: center; justify-items:center;">
  4633.                     <button title="Change Bounties"  id="${taskId}" value="${bountieInput || '1'}" class="assign-btn bounty-btn"
  4634.                     {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  4635.                     onclick="openBountyDropdown(${taskId},this)"
  4636.                     {% endif %} style="justify-content: center;width:35px;border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  4637.                     <div>${bountieInput || '-'}</div>
  4638.                     </button>
  4639.                 </td>
  4640.                
  4641.  
  4642.             `;
  4643.  
  4644.             // insert
  4645.             row.parentNode.insertBefore(newRow,row);
  4646.             row.remove();
  4647.  
  4648.            
  4649.            
  4650.             const subtaskCountSpan = taskRow.querySelector('.subtask-count');
  4651.             let currentCount = parseInt(subtaskCountSpan.textContent.replace(/\D/g, '')) || 0;
  4652.             currentCount++;
  4653.             subtaskCountSpan.textContent = `(${currentCount})`;
  4654.             document.removeEventListener('keydown', handleKeydown);
  4655.             updateProgress(taskRow);
  4656.             enforceTableCellHeight(35);
  4657.         }
  4658.        
  4659.         function updateParentTaskAfterDeletion(parentTaskId) {
  4660.             // Number(elem.querySelector('.subtask-count').innerText.match(/\((\d+)\)/)[1])
  4661.             const parentTask = document.getElementById(parentTaskId);
  4662.             if (parentTask) {
  4663.                 const remainingSubtasks = parentTask.querySelector('.subtask-count');
  4664.                 let remainingSubtasksCount = Number(remainingSubtasks.innerText.match(/\((\d+)\)/)[1]) - 1;
  4665.                 remainingSubtasks.innerText=`(${remainingSubtasksCount})`
  4666.                 const toggleSvg = parentTask.querySelector('#togglesvg');
  4667.                 const checkbox = parentTask.querySelector('.circular-checkbox');
  4668.                
  4669.                 if (remainingSubtasksCount === 0) {
  4670.                     if (toggleSvg) {
  4671.                         toggleSvg.style.display = 'none';
  4672.                     }
  4673.                     if (checkbox) {
  4674.                         checkbox.style.display = 'block';
  4675.                     }
  4676.                 }
  4677.             }
  4678.         }
  4679.  
  4680.         function addSubtaskRow(button,taskId) {
  4681.             // Find the row containing the button
  4682.             const addTaskRow = button.closest('tr');
  4683.             const isOpen = addTaskRow.dataset.open === 'true';
  4684.             const parentTask = button.closest('tr');
  4685.             const toggleSvg = parentTask.querySelector('#togglesvg');
  4686.             const checkbox = parentTask.querySelector('.circular-checkbox');
  4687.  
  4688.             if (toggleSvg) {
  4689.                 toggleSvg.style.display = 'flex';
  4690.                 if (checkbox) {
  4691.                     checkbox.style.display = 'none'; // Hide the checkbox when subtasks are added
  4692.                 }
  4693.             }
  4694.             let task_Row = button.closest('tr');
  4695.             let arrow_Svg = task_Row.querySelector('.arrow-svg');
  4696.             if (!isOpen && !arrow_Svg.classList.contains('rotated')){
  4697.                 addTaskRow.dataset.open = 'true';
  4698.                 arrow_Svg.classList.add('rotated');
  4699.                 toggleSubtask(button);
  4700.             }
  4701.             // Create a new row element
  4702.             const newRow = document.createElement('tr');
  4703.             newRow.classList.add ("task-row","add-task-row");
  4704.             newRow.style.textAlign = "left";
  4705.             newRow.style.height = "35px";
  4706.             rowIsOpen = true;
  4707.        
  4708.             // Create a cell that spans multiple columns
  4709.             const newCell = document.createElement('td');
  4710.             newCell.style.padding = "6px 0px 6px 60px";
  4711.             newCell.style.width = "50%";
  4712.             newCell.style.borderLeft = "1px solid #CED4DA";
  4713.             newCell.style.borderRight = "none";
  4714.             newCell.colSpan = "1";
  4715.             newCell.className = 'add-task-td';
  4716.        
  4717.             const newCell2 = document.createElement('td');
  4718.             // newCell2.style.width = "10%";
  4719.             newCell2.style.padding = "10px";
  4720.             // newCell2.style.display = "flex";
  4721.             // newCell2.style.flexDirection = "row";
  4722.             // newCell2.style.gap = "5px"; // Space between icons
  4723.             newCell2.colSpan = "3";
  4724.             newCell2.border = "none";
  4725.             newCell2.borderRight = "none";
  4726.             newCell2.borderLeft = "none";
  4727.        
  4728.             const newCell3 = document.createElement('td');
  4729.             newCell3.style.borderLeft = "none";
  4730.             newCell3.style.width = "10%";
  4731.             newCell3.colSpan = "2";
  4732.             newCell3.style.gap = "10px"; // Space between icons
  4733.             newCell3.borderRight = 'none';
  4734.            
  4735.             const taskInput = document.createElement('input');
  4736.             taskInput.type = "text";
  4737.             taskInput.classList.add("task-input-name","task-input");
  4738.             taskInput.placeholder = "Enter Task Name";
  4739.             taskInput.style.width = "100%";
  4740.  
  4741.             const iconBtnWrapper = document.createElement("div");
  4742.             iconBtnWrapper.classList.add('icon-btn-wrapper')
  4743.            
  4744.             // Helper function to create icon buttons with tooltip and onclick event
  4745.             function createIconButton(iconHTML, tooltipText, onClickHandler) {
  4746.                 const button = document.createElement('button');
  4747.                 button.className = "icon-button";
  4748.                 button.style.height = "30px";
  4749.                 button.style.width = "30px";
  4750.                 button.style.display = "flex";
  4751.                 button.style.alignItems = "center";
  4752.                 button.style.justifyContent = "center";
  4753.                 button.style.padding = "2px";
  4754.                 button.innerHTML = iconHTML;
  4755.                 button.title = tooltipText; // Tooltip
  4756.                 button.onclick = onClickHandler; // Assign onclick function
  4757.                 button.style.border = "2px solid #ababab";
  4758.                 return button;
  4759.             }
  4760.  
  4761.             let selectedPriority = "";
  4762.             let selectedDate = "";
  4763.             let selectedOption = "";
  4764.             let selectedMember = "";
  4765.             let selectedMemberData = {};
  4766.             let currentValue = "";
  4767.        
  4768.             // Your exact icons with tooltips and onclick handlers
  4769.             const priorityIcon = createIconButton(
  4770.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  4771.                 <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
  4772.                 <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
  4773.                 <g id="SVGRepo_iconCarrier">
  4774.                     <path
  4775.                         id="priority-icon-path-add"
  4776.                         d="M12 4L20 20H4L12 4Z"
  4777.                         fill = "none"
  4778.                         stroke="#ababab"
  4779.                         stroke-width="1.5"
  4780.                         stroke-linecap="round"
  4781.                         stroke-linejoin="round"
  4782.                     />
  4783.                     <path
  4784.                         d="M12 8L12 12"
  4785.                         id = "priority-icon-exclamation-add"
  4786.                         stroke="#ababab"
  4787.                             stroke-width="1.5"
  4788.                             stroke-linecap="round"
  4789.                             stroke-linejoin="round"
  4790.                         />
  4791.                         <path
  4792.                         id = "priority-iconborder-add"
  4793.                             d="M12 16.01L12.01 15.9989"
  4794.                             stroke="#ababab"
  4795.                             stroke-width="1.5"
  4796.                             stroke-linecap="round"
  4797.                             stroke-linejoin="round"
  4798.                         />
  4799.                     </g>
  4800.                 </svg>
  4801.                     `,
  4802.                 "Assign Priority",
  4803.                 () => {
  4804.                     // Check if the dropdown is already visible and remove it
  4805.                     const existingDropdown = document.querySelector('.custom-dropdown');
  4806.                     if (existingDropdown) {
  4807.                         existingDropdown.remove();
  4808.                         return; // Don't create a new dropdown if one is already visible
  4809.                     }
  4810.  
  4811.                     // Create the custom dropdown for priority options
  4812.                     let dropdown = document.createElement('div');
  4813.                     dropdown.className = 'custom-dropdown';
  4814.                     dropdown.style.position = 'absolute';
  4815.                     dropdown.style.background = 'white';
  4816.                     dropdown.style.border = '1px solid #ddd';
  4817.                     dropdown.style.padding = '5px';
  4818.                     dropdown.style.zIndex = '1000';
  4819.                     dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  4820.                     dropdown.style.maxHeight = '200px';
  4821.                     dropdown.style.overflowY = 'auto';
  4822.                     dropdown.style.minWidth = '200px';
  4823.  
  4824.                     // Define the priority options
  4825.                     const priorities = {
  4826.                         urgent: "Urgent",
  4827.                         high: "High",
  4828.                         normal: "Normal",
  4829.                         low: "Low"
  4830.                     };
  4831.  
  4832.                     // Create the dropdown options
  4833.                     Object.keys(priorities).forEach(priority => {
  4834.                         const option = document.createElement('div');
  4835.                         option.textContent = priorities[priority];
  4836.                         option.style.padding = '5px 10px';
  4837.                         option.style.cursor = 'pointer';
  4838.                         option.style.backgroundColor = 'white';
  4839.  
  4840.                         // Hover effect for the dropdown items
  4841.                         option.addEventListener('mouseover', () => {
  4842.                             option.style.backgroundColor = '#f1f1f1';
  4843.                         });
  4844.                         option.addEventListener('mouseout', () => {
  4845.                             option.style.backgroundColor = 'white';
  4846.                         });
  4847.  
  4848.                         // When an option is selected, update the flag color
  4849.                         option.addEventListener('click', () => {
  4850.                             selectedPriority = priority;
  4851.                             const priorityIconPath = document.getElementById('priority-icon-path-add');
  4852.                             const priorityIconExc = document.getElementById('priority-iconborder-add');
  4853.                             const priorityOutline = document.getElementById('priority-icon-exclamation-add');
  4854.  
  4855.  
  4856.                             // Define color changes for different priorities
  4857.                             const colors = {
  4858.                                 urgent: "red",
  4859.                                 high: "gold",
  4860.                                 normal: "transparent",
  4861.                                 low: "grey"
  4862.                             };
  4863.  
  4864.                             // Change the color of the flag icon based on selected priority
  4865.                             if (selectedPriority !== "none") {
  4866.                                 priorityIconPath.setAttribute('fill', colors[selectedPriority]);
  4867.                                 priorityIconPath.setAttribute('stroke',colors[selectedPriority]);
  4868.                                 if (colors[selectedPriority] == "red" )
  4869.                                 {
  4870.                                     priorityIconExc.setAttribute('stroke', 'white');
  4871.                                    
  4872.                                 }
  4873.                                 else if (colors[selectedPriority] == "transparent"){
  4874.                                     priorityOutline.setAttribute('stroke', 'grey');
  4875.                                     priorityIconPath.setAttribute('stroke', 'grey');
  4876.                                 }
  4877.                                 else{
  4878.                                     priorityIconExc.setAttribute('stroke', 'black');
  4879.                                     priorityOutline.setAttribute('stroke', 'black');
  4880.                                 }
  4881.                                
  4882.                             }
  4883.  
  4884.                             // Remove the dropdown after selection
  4885.                             dropdown.remove();
  4886.                         });
  4887.  
  4888.                         dropdown.appendChild(option);
  4889.                     });
  4890.  
  4891.                     // Create a "Clear" button as part of the dropdown
  4892.                     const clearButton = document.createElement('button');
  4893.                     clearButton.textContent = 'Clear';
  4894.                     clearButton.style.padding = '5px 10px';
  4895.                     clearButton.style.marginTop = '10px';
  4896.                     clearButton.style.cursor = 'pointer';
  4897.                     clearButton.style.border = 'none';
  4898.                     clearButton.style.background = "lightgrey";
  4899.  
  4900.                     // When the "Clear" button is clicked, reset to original state
  4901.                     clearButton.addEventListener('click', () => {
  4902.                         const priorityIconPath = document.getElementById('priority-icon-path');
  4903.                         priorityIconPath.setAttribute('fill', 'none');
  4904.                         priorityIconPath.setAttribute('stroke', '#ababab');
  4905.                        
  4906.                         // Remove the dropdown after clicking "Clear"
  4907.                         dropdown.remove();
  4908.                     });
  4909.  
  4910.                     dropdown.appendChild(clearButton);
  4911.  
  4912.                     // Position the dropdown below the icon
  4913.                     const rect = priorityIcon.getBoundingClientRect();
  4914.                     const zoomFactor = 1; // Optional zoom adjustment
  4915.  
  4916.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  4917.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  4918.  
  4919.                     document.body.appendChild(dropdown);
  4920.                     const handleClickOutside = (event) => {
  4921.                         if (!priorityIcon.contains(event.target)) {
  4922.                             dropdown.remove();
  4923.                             document.removeEventListener('click', handleClickOutside);
  4924.                         }
  4925.                     };
  4926.                     document.addEventListener('click', handleClickOutside);
  4927.  
  4928.                 }
  4929.             );
  4930.  
  4931.            
  4932.             const taskIcon = createIconButton(
  4933.                 `<svg width="30px" height="30px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#000000">
  4934.  
  4935.                 <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  4936.  
  4937.                 <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  4938.  
  4939.                 <g id="SVGRepo_iconCarrier"> <path color="#000000" d="M7.992 0A2.008 2.008 0 0 0 6 2H5c-.657 0-1.178.06-1.617.225-.439.164-.79.461-.998.838-.415.752-.37 1.673-.385 2.931v5.012c.015 1.258-.03 2.179.385 2.932.208.376.56.673.998.838.439.164.96.224 1.617.224h3.133c.021-.05.031-.102.059-.15l.482-.85H5c-.592 0-1.006-.063-1.265-.16-.26-.098-.372-.203-.473-.387C3.06 13.087 3.015 12.259 3 11V6c.015-1.259.06-2.087.262-2.453.101-.184.213-.29.473-.387C3.995 3.062 4.408 3 5 3v.999h6V3c.593 0 1.006.063 1.266.16.26.098.371.203.472.387.202.366.247 1.194.262 2.453v2.832c.31.115.582.323.752.62v.001l.248.438V5.994c-.015-1.258.031-2.179-.385-2.932a1.88 1.88 0 0 0-.998-.837C12.179 2.06 11.657 2 11 2H9.996a2.008 2.008 0 0 0-1.992-2zm.01 1c.559 0 1 .442 1 1a.99.99 0 0 1-1 1 .982.982 0 0 1-.922-.61A1.01 1.01 0 0 1 7.003 2c0-.558.441-1 1-1zM5 6v1h6.012V6zm0 2v1h6.012V8zm-.01 2v1h3v-1z" fill="gray" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal;marker:none" white-space="normal"/> <path class="warning" color="#000000" d="M12.48 9.729a.443.443 0 0 0-.36.22l-3.061 5.397a.437.437 0 0 0 .379.654h6.125a.437.437 0 0 0 .379-.654l-3.059-5.397a.442.442 0 0 0-.402-.22zM12 11h1v.168c0 .348-.016.667-.047.957-.03.29-.069.581-.115.875h-.666a12.898 12.898 0 0 1-.125-.875 9.146 9.146 0 0 1-.047-.957zm.5 3a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1z" fill="#ababab" fill-rule="evenodd" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal" white-space="normal"/> </g>
  4940.  
  4941.                 </svg>`,
  4942.                 "Select Type", // Default text on the button
  4943.                 () => {
  4944.                     // Check if the dropdown is already visible and remove it
  4945.                     const existingDropdown = document.querySelector('.custom-dropdown');
  4946.                     if (existingDropdown) {
  4947.                         existingDropdown.remove();
  4948.                         return; // Don't create a new dropdown if one is already visible
  4949.                     }
  4950.  
  4951.                     // Create the dropdown container
  4952.                     let dropdown = document.createElement('div');
  4953.                     dropdown.className = 'custom-dropdown';
  4954.                                 dropdown.style.position = 'absolute';
  4955.                                 dropdown.style.background = 'white';
  4956.                                 dropdown.style.border = 'none';
  4957.                                 dropdown.style.padding = '4px 0';
  4958.                                 dropdown.style.zIndex = '1000';
  4959.                                 dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  4960.                                 dropdown.style.maxHeight = '200px';
  4961.                                 dropdown.style.overflowY = 'auto';
  4962.                                 dropdown.style.minWidth = '200px';
  4963.                                 dropdown.style.borderRadius = '8px';
  4964.  
  4965.                     // Define the options for Task/Checkpoint
  4966.                     const options = [
  4967.                         {
  4968.                             title: "Task",
  4969.                             icon: `<svg width="24px" height="24px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#000000">
  4970.  
  4971.                             <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  4972.  
  4973.                             <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  4974.  
  4975.                             <g id="SVGRepo_iconCarrier"> <path color="#000000" d="M7.992 0A2.008 2.008 0 0 0 6 2H5c-.657 0-1.178.06-1.617.225-.439.164-.79.461-.998.838-.415.752-.37 1.673-.385 2.931v5.012c.015 1.258-.03 2.179.385 2.932.208.376.56.673.998.838.439.164.96.224 1.617.224h3.133c.021-.05.031-.102.059-.15l.482-.85H5c-.592 0-1.006-.063-1.265-.16-.26-.098-.372-.203-.473-.387C3.06 13.087 3.015 12.259 3 11V6c.015-1.259.06-2.087.262-2.453.101-.184.213-.29.473-.387C3.995 3.062 4.408 3 5 3v.999h6V3c.593 0 1.006.063 1.266.16.26.098.371.203.472.387.202.366.247 1.194.262 2.453v2.832c.31.115.582.323.752.62v.001l.248.438V5.994c-.015-1.258.031-2.179-.385-2.932a1.88 1.88 0 0 0-.998-.837C12.179 2.06 11.657 2 11 2H9.996a2.008 2.008 0 0 0-1.992-2zm.01 1c.559 0 1 .442 1 1a.99.99 0 0 1-1 1 .982.982 0 0 1-.922-.61A1.01 1.01 0 0 1 7.003 2c0-.558.441-1 1-1zM5 6v1h6.012V6zm0 2v1h6.012V8zm-.01 2v1h3v-1z" fill="gray" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal;marker:none" white-space="normal"/> <path class="warning" color="#000000" d="M12.48 9.729a.443.443 0 0 0-.36.22l-3.061 5.397a.437.437 0 0 0 .379.654h6.125a.437.437 0 0 0 .379-.654l-3.059-5.397a.442.442 0 0 0-.402-.22zM12 11h1v.168c0 .348-.016.667-.047.957-.03.29-.069.581-.115.875h-.666a12.898 12.898 0 0 1-.125-.875 9.146 9.146 0 0 1-.047-.957zm.5 3a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1z" fill="#ababab" fill-rule="evenodd" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal" white-space="normal"/> </g>
  4976.  
  4977.                             </svg>`
  4978.                         },
  4979.                         {
  4980.                             title: "Checkpoint",
  4981.                             icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16" fill="#000000">
  4982.  
  4983.                             <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  4984.  
  4985.                             <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  4986.  
  4987.                             <g id="SVGRepo_iconCarrier"> <path fill="#ababab" fill-rule="evenodd" d="M4,4 L9,4 C9.55228,4 10,3.55228 10,3 C10,2.44772 9.55228,2 9,2 L4,2 C2.89543,2 2,2.89543 2,4 L2,12 C2,13.1046 2.89543,14 4,14 L12,14 C13.1046,14 14,13.1046 14,12 L14,10 C14,9.44771 13.5523,9 13,9 C12.4477,9 12,9.44771 12,10 L12,12 L4,12 L4,4 Z M15.2071,2.29289 C14.8166,1.90237 14.1834,1.90237 13.7929,2.29289 L8.5,7.58579 L7.70711,6.79289 C7.31658,6.40237 6.68342,6.40237 6.29289,6.79289 C5.90237,7.18342 5.90237,7.81658 6.29289,8.20711 L7.79289,9.70711 C7.98043,9.89464 8.23478,10 8.5,10 C8.76522,10 9.01957,9.89464 9.20711,9.70711 L15.2071,3.70711 C15.5976,3.31658 15.5976,2.68342 15.2071,2.29289 Z"/> </g>
  4988.  
  4989.                             </svg>`
  4990.                         },
  4991.                     ];
  4992.  
  4993.                     // Create dropdown options
  4994.                     options.forEach(option => {
  4995.                         const item = document.createElement('div');
  4996.                         item.style.cursor = 'pointer';
  4997.                         item.style.padding = '8px 10px';
  4998.                         item.style.backgroundColor = 'white';
  4999.                         item.style.display ="flex";
  5000.                         item.style.flexDirection ="row";
  5001.                         item.style.gap = "8px"
  5002.                        
  5003.                         item.innerHTML = `${option.icon} ${option.title}`;
  5004.                        
  5005.                         // Add click handler to set the button text and close the dropdown
  5006.                         item.addEventListener('click', () => {
  5007.                             selectedOption = option.title;
  5008.                             taskIcon.innerHTML = option.icon; // Update button text
  5009.                             dropdown.remove(); // Close the dropdown
  5010.                         });
  5011.  
  5012.                         dropdown.appendChild(item);
  5013.                     });
  5014.  
  5015.                     // Append the dropdown to the button's position
  5016.                     taskIcon.appendChild(dropdown);
  5017.                     const rect = taskIcon.getBoundingClientRect();
  5018.                     const zoomFactor = 1; // Optional zoom adjustment
  5019.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  5020.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  5021.                     document.body.appendChild(dropdown);
  5022.                     const handleClickOutside = (event) => {
  5023.                         if (!taskIcon.contains(event.target)) {
  5024.                             dropdown.remove();
  5025.                             document.removeEventListener('click', handleClickOutside);
  5026.                         }
  5027.                     };
  5028.                     document.addEventListener('click', handleClickOutside);
  5029.                 }
  5030.             );
  5031.            
  5032.  
  5033.             const bountyIcon = createIconButton(
  5034.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512" fill="#000000">
  5035.                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5036.                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5037.                     <g id="SVGRepo_iconCarrier">
  5038.                     <title>ionicons-v5-p</title>
  5039.                     <circle cx="256" cy="160" r="128" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5040.                     <path d="M143.65,227.82,48,400l86.86-.42a16,16,0,0,1,13.82,7.8L192,480l88.33-194.32" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5041.                     <path d="M366.54,224,464,400l-86.86-.42a16,16,0,0,0-13.82,7.8L320,480,256,339.2" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5042.                     <circle cx="256" cy="160" r="64" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5043.                     </g>
  5044.                     </svg>`,
  5045.                     "Assign Bounties",  
  5046.                     () => {
  5047.                         // If the current element is an input field, save the value and revert to the text
  5048.                         const container = document.createElement('div');
  5049.                         container.classList.add('bounty-container');
  5050.                         container.style.display = 'inline-flex';
  5051.                         container.style.alignItems = 'center';  // Align items vertically centered
  5052.                         container.style.gap = '5px';  // Small gap between icon and input
  5053.                         container.style.width = '35px';  // Fixed width for the container
  5054.                
  5055.                         // Create input field if clicking on the current text
  5056.                         const inputField = document.createElement('input');
  5057.                         inputField.type = 'text';
  5058.                         inputField.className = 'bounty-input';
  5059.                         inputField.value = currentValue;  // Set the current value in the input
  5060.                         inputField.style.width = '35px';  // Match the width
  5061.                         inputField.style.padding = '5px';
  5062.                         inputField.style.fontSize = '16px';
  5063.                         inputField.style.textAlign = 'center';
  5064.                         inputField.style.border = '1px solid #ababab';
  5065.                         inputField.style.borderRadius = '4px';
  5066.                         inputField.style.backgroundColor = 'transparent';  // Keep background transparent
  5067.                         inputField.style.color = '#ababab';  // Match the SVG color
  5068.                
  5069.                         // Append the input field into the container
  5070.                         container.appendChild(inputField);
  5071.                
  5072.                         // Replace the SVG or text with the container holding the input field
  5073.                         bountyIcon.innerHTML = '';
  5074.                         bountyIcon.appendChild(container);
  5075.                
  5076.                         // Focus the input field when it's displayed
  5077.                         inputField.focus();
  5078.                         const value = inputField.value.trim();  // Get the trimmed value
  5079.                             if (value) {
  5080.                                 currentValue = value;  // Save the value entered by the user
  5081.                                 currentHtml = value;}
  5082.                         // When the user finishes editing (on blur), save the value and update the display
  5083.                         inputField.addEventListener('blur', function () {
  5084.                             const value = inputField.value.trim();  // Get the trimmed value
  5085.                
  5086.                             // If the input is not empty, save the new value
  5087.                             if (value) {
  5088.                                 currentValue = value;  // Save the value entered by the user
  5089.                                 currentHtml = value;
  5090.                             }
  5091.                             else {
  5092.                                 currentValue = "";
  5093.                                 currentHtml = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512" fill="#000000">
  5094.                         <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5095.                         <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5096.                         <g id="SVGRepo_iconCarrier">
  5097.                         <title>ionicons-v5-p</title>
  5098.                         <circle cx="256" cy="160" r="128" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5099.                         <path d="M143.65,227.82,48,400l86.86-.42a16,16,0,0,1,13.82,7.8L192,480l88.33-194.32" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5100.                         <path d="M366.54,224,464,400l-86.86-.42a16,16,0,0,0-13.82,7.8L320,480,256,339.2" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5101.                         <circle cx="256" cy="160" r="64" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5102.                         </g>
  5103.                     </svg>`
  5104.                             }
  5105.                
  5106.                             // Revert the icon to show the current value (either new or original)
  5107.                             bountyIcon.innerHTML = currentHtml;
  5108.                             bountyIcon.style.width = "35px";
  5109.                             bountyIcon.style.minWidth = "35px";
  5110.                             bountyIcon.style.color =  '#ababab';
  5111.                         });
  5112.                     }
  5113.             );
  5114.            
  5115.             const assignIcon = createIconButton(
  5116.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5117.                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5118.                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5119.                     <g id="SVGRepo_iconCarrier">
  5120.                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" fill="#ABABAB"/>
  5121.                     </g>
  5122.                 </svg>`,
  5123.                 "Select Assignee",
  5124.                 () => {
  5125.                     // Check if the dropdown is already visible and remove it
  5126.                     const existingDropdown = document.querySelector('.custom-dropdown');
  5127.                     if (existingDropdown) {
  5128.                         existingDropdown.remove();
  5129.                         return;
  5130.                     }
  5131.            
  5132.                     // Create the custom dropdown for team members
  5133.                     let dropdown = document.createElement('div');
  5134.                     dropdown.className = 'custom-dropdown';
  5135.                     dropdown.style.position = 'absolute';
  5136.                     dropdown.style.background = 'white';
  5137.                     dropdown.style.border = '1px solid #ddd';
  5138.                     dropdown.style.padding = '0';
  5139.                     dropdown.style.zIndex = '1000';
  5140.                     dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  5141.                     dropdown.style.maxHeight = '300px';
  5142.                     dropdown.style.overflowY = 'auto';
  5143.            
  5144.                     // Add search input to filter the team members
  5145.                     searchInputWrapper.classList.add('search-input-wrapper')
  5146.                     searchInputWrapper.style.width = '100%';
  5147.                     searchInputWrapper.style.padding = '10px';
  5148.                     let searchInput = document.createElement('input');
  5149.                     searchInput.type = 'text';
  5150.                     searchInput.placeholder = 'Search team members';
  5151.                     searchInput.style.width = '90%';
  5152.                     searchInput.style.padding = '5px';
  5153.                     searchInput.style.margin = '10px';
  5154.                     searchInput.style.border = '1px solid #ddd';
  5155.                     searchInput.style.borderRadius = '4px';
  5156.                     searchInput.style.boxSizing = 'border-box';
  5157.                     searchInput.id='searchInput'
  5158.                     // searchInputWrapper.appendChild(searchInput)
  5159.                     // Append search input to the dropdown
  5160.                     dropdown.appendChild(searchInput);
  5161.            
  5162.                     // Container for member list
  5163.                     let memberList = document.createElement('div');
  5164.                     dropdown.appendChild(memberList);
  5165.            
  5166.                     // Populate dropdown with team members
  5167.                     team_members.forEach(member => {
  5168.                         const memberItem = document.createElement('div');
  5169.                         memberItem.textContent = member.name;
  5170.                         memberItem.style.padding = '5px 10px';
  5171.                         memberItem.style.cursor = 'pointer';
  5172.                         memberItem.style.backgroundColor = 'white';
  5173.            
  5174.                         // Hover effect for the dropdown items
  5175.                         memberItem.addEventListener('mouseover', () => {
  5176.                             memberItem.style.backgroundColor = '#f1f1f1';
  5177.                         });
  5178.                         memberItem.addEventListener('mouseout', () => {
  5179.                             memberItem.style.backgroundColor = 'white';
  5180.                         });
  5181.            
  5182.                         // When a member is selected
  5183.                         memberItem.addEventListener('click', () => {
  5184.                             const initials = getInitials(member.name);
  5185.                             createInitialsCircle(initials, member.name); // Replace with initials circle
  5186.                             selectedMember = member.name;
  5187.                             selectedMemberData = {"id":member.id,"name":member.name};
  5188.                             dropdown.remove(); // Remove the dropdown
  5189.                         });
  5190.            
  5191.                         memberList.appendChild(memberItem);
  5192.                     });
  5193.            
  5194.                     // Position the dropdown below the icon
  5195.                     const rect = assignIcon.getBoundingClientRect();
  5196.                     const zoomFactor = 1; // Get the zoom level
  5197.            
  5198.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  5199.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  5200.            
  5201.                     document.body.appendChild(dropdown);
  5202.  
  5203.                     const handleClickOutside = (event) => {
  5204.                         if (!assignIcon.contains(event.target) && !(event.target.id == "searchInput")) {
  5205.                             dropdown.remove();
  5206.                             document.removeEventListener('click', handleClickOutside);
  5207.                         }
  5208.                     };
  5209.                     document.addEventListener('click', handleClickOutside);
  5210.  
  5211.            
  5212.                     // Search functionality
  5213.                     searchInput.addEventListener('input', function () {
  5214.                         const query = searchInput.value.toLowerCase();
  5215.                         const items = memberList.querySelectorAll('div');
  5216.                         items.forEach(item => {
  5217.                             const text = item.textContent.toLowerCase();
  5218.                             if (text.indexOf(query) === -1) {
  5219.                                 item.style.display = 'none';
  5220.                             } else {
  5221.                                 item.style.display = 'block';
  5222.                             }
  5223.                         });
  5224.                     });
  5225.            
  5226.                     // Clear button functionality
  5227.                     const clearButton = document.createElement('button');
  5228.                     clearButton.textContent = 'Clear';
  5229.                     clearButton.style.padding = '5px 10px';
  5230.                     clearButton.style.margin = '10px';
  5231.                     clearButton.style.cursor = 'pointer';
  5232.                     clearButton.style.border = 'none';
  5233.                     clearButton.style.borderRadius = '4px';
  5234.                     clearButton.style.fontSize = '14px';
  5235.                     clearButton.style.background = "lightgrey";
  5236.            
  5237.                     clearButton.addEventListener('click', () => {
  5238.                         selectedMember = 'none'; // Set selected member to "none"
  5239.                         selectedMemberData = {};
  5240.                         assignIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5241.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5242.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5243.                                                     <g id="SVGRepo_iconCarrier">
  5244.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" fill="#ABABAB"/>
  5245.                                                     </g>
  5246.                                                 </svg>`; // Reset to the original SVG
  5247.                         dropdown.remove();
  5248.                     });
  5249.                    
  5250.                     dropdown.appendChild(clearButton);
  5251.                    
  5252.                 }
  5253.             );
  5254.            
  5255.  
  5256.             function getInitials(username) {
  5257.                 const nameParts = username.trim().split(/\s+/);
  5258.                 return nameParts.map(part => part[0].toUpperCase()).join('');
  5259.             }
  5260.  
  5261.             function createInitialsCircle(initials, username) {
  5262.                 // Create the circle element for initials
  5263.                 const circle = document.createElement('div');
  5264.                 circle.className = 'initials-circle';
  5265.                 circle.style.width = '25px';
  5266.                 circle.style.height = '25px';
  5267.                 circle.style.borderRadius = '50%';
  5268.                 circle.style.display = 'flex';
  5269.                 circle.style.alignItems = 'center';
  5270.                 circle.style.justifyContent = 'center';
  5271.                 circle.style.backgroundColor = '#7c4dff';
  5272.                 circle.style.color = '#fff';
  5273.                 circle.style.cursor = 'pointer';
  5274.                 circle.style.fontSize = '14px';
  5275.                 circle.textContent = initials;
  5276.  
  5277.                 // Replace the assign icon with the circle containing the initials
  5278.                 assignIcon.innerHTML = '';  // Clear previous icon
  5279.                 assignIcon.appendChild(circle);
  5280.                
  5281.                
  5282.                 assignIcon.title = username;
  5283.  
  5284.                 // When the circle is clicked, open the dropdown again
  5285.                 circle.addEventListener('click', () => {
  5286.                     createIconButton(assignIcon.innerHTML, "Assign", () => {
  5287.                         openDropdown();
  5288.                     });
  5289.                 });
  5290.             }
  5291.  
  5292.            // Create the date icon button (SVG for the calendar)
  5293.            
  5294.             const dateIcon = createIconButton(
  5295.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5296.                     <g id="SVGRepo_iconCarrier">
  5297.                         <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  5298.                     </g>
  5299.                 </svg>`,
  5300.                 "Select Date",
  5301.                 () => {
  5302.                     // Check if the date picker is already visible and remove it
  5303.                     const existingDropdown = document.querySelector('.date-picker-dropdown');
  5304.                     if (existingDropdown) {
  5305.                         existingDropdown.remove();
  5306.                         return; // Don't create a new dropdown if one is already visible
  5307.                     }
  5308.                
  5309.                     // Create the date input field (it will appear as a dropdown)
  5310.                     const dateInput = document.createElement('input');
  5311.                     dateInput.type = 'date';
  5312.                     dateInput.className = 'date-icon-input'; // Add class for styling
  5313.                
  5314.                     // Create a dropdown container for the date input field
  5315.                     const dropdown = document.createElement('div');
  5316.                     dropdown.classList.add('date-picker-dropdown', 'input-style');
  5317.                     dropdown.style.position = 'absolute';
  5318.                     dropdown.style.zIndex = '9999';  
  5319.                     dropdown.style.width = "200px";
  5320.                     const rect = dateIcon.getBoundingClientRect();
  5321.                     const zoomFactor = 1;
  5322.                
  5323.                     dropdown.style.left = `${rect.left / zoomFactor}px`;
  5324.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`;
  5325.                
  5326.                     dropdown.appendChild(dateInput);
  5327.                
  5328.                     // Create a "Clear" button in the next row
  5329.                     const clearButton = document.createElement('button');
  5330.                     clearButton.textContent = 'Clear';
  5331.                     clearButton.classList.add('clear-button');
  5332.                     clearButton.style.marginTop = '10px';
  5333.                     clearButton.style.padding = '5px 10px';
  5334.                     clearButton.style.cursor = 'pointer';
  5335.                     clearButton.style.backgroundColor = '#f0f0f0';
  5336.                     clearButton.style.border = '1px solid #ddd';
  5337.                     clearButton.style.borderRadius = '4px';
  5338.                     clearButton.style.fontSize = '14px';
  5339.                
  5340.                     // When the "Clear" button is clicked, reset the input and icon
  5341.                     clearButton.addEventListener('click', () => {
  5342.                         dateInput.value = ''; // Reset the date input
  5343.                         dateIcon.style.width = "35px";
  5344.                         dateIcon.style.minWidth = "35px";
  5345.                         dateIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5346.                     <g id="SVGRepo_iconCarrier">
  5347.                         <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  5348.                     </g>
  5349.                 </svg>`; // Reset the date icon text
  5350.                         dropdown.remove(); // Remove the dropdown
  5351.                     });
  5352.                
  5353.                     dropdown.appendChild(clearButton);
  5354.                
  5355.                     // Append the dropdown to the body
  5356.                     document.body.appendChild(dropdown);
  5357.                
  5358.                     const handleClickOutside = (event) => {
  5359.                         if (!dateIcon.contains(event.target) && !dateInput.contains(event.target)) {
  5360.                             dropdown.remove();
  5361.                             document.removeEventListener('click', handleClickOutside);
  5362.                         }
  5363.                     };
  5364.                     document.addEventListener('click', handleClickOutside);
  5365.                     // When a date is selected, update the icon HTML with the selected date
  5366.                     dateInput.addEventListener('change', function () {
  5367.                         selectedDate = new Date(this.value);
  5368.                         const formattedDate = selectedDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: '2-digit' });
  5369.                        
  5370.                         // Update the icon's HTML with the selected date
  5371.                         dateIcon.innerHTML = `${formattedDate}`;
  5372.                         dateIcon.offsetWidth;  
  5373.                         dateIcon.style.width = "auto";
  5374.                         dateIcon.style.minWidth = "100px";  // Adjust this as per your needs
  5375.                         // Hide the dropdown after date selection
  5376.                         dropdown.remove();
  5377.                     });
  5378.                 }
  5379.             );
  5380.  
  5381.            
  5382.             const saveButton = document.createElement('button');
  5383.             saveButton.className = "save-button";
  5384.             saveButton.textContent = "Save";
  5385.             saveButton.style.margin = "0px 10px";
  5386.             saveButton.title = "Save Task";
  5387.  
  5388.             function handleKeydown(event) {
  5389.                
  5390.                 if (event.key === 'Enter' && rowIsOpen) {
  5391.                     event.preventDefault();
  5392.                     saveData();
  5393.                 }
  5394.             }
  5395.             const saveData = () => {
  5396.                
  5397.                 const data = {
  5398.                     "priority": selectedPriority,
  5399.                     "member": selectedMemberData, // format: {id: some id, name: some name}
  5400.                     "date": selectedDate,
  5401.                     "bounty": currentValue,
  5402.                     "type": selectedOption,
  5403.                     "name": taskInput.value,
  5404.                     "parent" : taskId
  5405.                 };
  5406.                 selectedPriority = "";
  5407.                 selectedDate = "";
  5408.                 selectedOption = "";
  5409.                 selectedMember = "";
  5410.                 selectedMemberData = {};
  5411.                 currentValue = "";
  5412.                 taskInput.value = "";
  5413.                
  5414.                 addSubtask(button, data,handleKeydown,newRow);
  5415.                
  5416.  
  5417.                
  5418.                
  5419.             };
  5420.  
  5421.             // Add event listener to save button
  5422.             saveButton.addEventListener('click', saveData);
  5423.            
  5424.             document.addEventListener('keydown', handleKeydown);
  5425.             const cancelButton = document.createElement('button');
  5426.             cancelButton.className = "cancel-button";
  5427.             cancelButton.textContent = "Cancel";
  5428.             cancelButton.title = "Cancel";
  5429.            
  5430.             cancelButton.addEventListener('click', () => {
  5431.                 const rowToRemove = cancelButton.closest('tr');  
  5432.                 if (rowToRemove) {
  5433.                     rowToRemove.remove();
  5434.                     rowIsOpen = false;
  5435.                     document.removeEventListener('keydown', handleKeydown);
  5436.                 }
  5437.             });
  5438.             newCell.appendChild(taskInput);
  5439.             newRow.appendChild(newCell);
  5440.  
  5441.             iconBtnWrapper.append(taskIcon, assignIcon, priorityIcon, bountyIcon, dateIcon);
  5442.             newCell2.append(iconBtnWrapper);
  5443.             newCell3.append(saveButton, cancelButton);
  5444.             newRow.appendChild(newCell2);
  5445.             newRow.appendChild(newCell3);
  5446.            
  5447.            
  5448.             if (addTaskRow) {
  5449.                
  5450.                 let nextRow = addTaskRow.nextElementSibling;
  5451.                
  5452.                 while (nextRow && nextRow.classList.contains('subtask-row')) {
  5453.                     nextRow = nextRow.nextElementSibling;
  5454.  
  5455.                 }
  5456.                
  5457.                
  5458.                 nextRow.insertAdjacentElement('beforebegin', newRow);
  5459.                 enforceTableCellHeight(35);
  5460.                 taskInput.focus();
  5461.            
  5462.             }
  5463.         }
  5464.  
  5465.         let rowIsOpen = false;
  5466.         function addTaskRow(button) {
  5467.             let addTaskTr = button.parentElement.parentElement;
  5468.             addTaskTr.classList.add('hidden')
  5469.             rowIsOpen = true;
  5470.             // Find the row containing the button
  5471.             const addTaskRow = button.closest('tr');
  5472.            
  5473.             // Create a new row element
  5474.             const newRow = document.createElement('tr');
  5475.             newRow.classList.add ("task-row","add-task-row");
  5476.             newRow.style.textAlign = "left";
  5477.             newRow.style.height = "40px";
  5478.             rowIsOpen = true;
  5479.        
  5480.             // Create a cell that spans multiple columns
  5481.             const newCell = document.createElement('td');
  5482.             newCell.style.padding = "6px 36px";
  5483.             newCell.style.width = "50%";
  5484.             newCell.style.borderLeft = "1px solid #CED4DA";
  5485.             newCell.style.borderRight = "none";
  5486.             newCell.colSpan = "1";
  5487.             newCell.className = 'add-task-td';
  5488.        
  5489.             const newCell2 = document.createElement('td');
  5490.             newCell2.style.borderRight = "none";
  5491.             newCell2.style.borderLeft = "none";
  5492.             // newCell2.style.width = "10%";
  5493.             newCell2.style.padding = "10px";
  5494.             // newCell2.style.display = "flex";
  5495.             // newCell2.style.flexDirection = "row";
  5496.             // newCell2.style.gap = "5px"; // Space between icons
  5497.             newCell2.colSpan = "3";
  5498.        
  5499.             const newCell3 = document.createElement('td');
  5500.             newCell3.style.borderLeft = "none";
  5501.             newCell3.style.width = "10%";
  5502.             newCell3.colSpan = "2";
  5503.             newCell3.style.gap = "10px"; // Space between icons
  5504.            
  5505.             const taskInput = document.createElement('input');
  5506.             taskInput.type = "text";
  5507.             taskInput.classList.add("task-input-name","task-input");
  5508.             taskInput.placeholder = "Enter Task Name";
  5509.             taskInput.style.width = "100%";
  5510.  
  5511.             const iconBtnWrapper = document.createElement("div");
  5512.             iconBtnWrapper.classList.add('icon-btn-wrapper')
  5513.            
  5514.             // Helper function to create icon buttons with tooltip and onclick event
  5515.             function createIconButton(iconHTML, tooltipText, onClickHandler) {
  5516.                 const button = document.createElement('button');
  5517.                 button.className = "icon-button";
  5518.                 button.style.height = "30px";
  5519.                 button.style.width = "30px";
  5520.                 button.style.display = "flex";
  5521.                 button.style.alignItems = "center";
  5522.                 button.style.justifyContent = "center";
  5523.                 button.style.padding = "2px";
  5524.                 button.innerHTML = iconHTML;
  5525.                 button.title = tooltipText; // Tooltip
  5526.                 button.onclick = onClickHandler; // Assign onclick function
  5527.                 button.style.border = "2px solid #ababab";
  5528.                 return button;
  5529.             }
  5530.  
  5531.             let selectedPriority = "";
  5532.             let selectedDate = "";
  5533.             let selectedOption = "";
  5534.             let selectedMember = "";
  5535.             let selectedMemberData = {};
  5536.             let currentValue = "";
  5537.        
  5538.             // Your exact icons with tooltips and onclick handlers
  5539.             const priorityIcon = createIconButton(
  5540.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5541.                 <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
  5542.                 <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
  5543.                 <g id="SVGRepo_iconCarrier">
  5544.                     <path
  5545.                         id="priority-icon-path-add"
  5546.                         d="M12 4L20 20H4L12 4Z"
  5547.                         fill = "none"
  5548.                         stroke="#ababab"
  5549.                         stroke-width="1.5"
  5550.                         stroke-linecap="round"
  5551.                         stroke-linejoin="round"
  5552.                     />
  5553.                     <path
  5554.                         d="M12 8L12 12"
  5555.                         id = "priority-icon-exclamation-add"
  5556.                         stroke="#ababab"
  5557.                             stroke-width="1.5"
  5558.                             stroke-linecap="round"
  5559.                             stroke-linejoin="round"
  5560.                         />
  5561.                         <path
  5562.                         id = "priority-iconborder-add"
  5563.                             d="M12 16.01L12.01 15.9989"
  5564.                             stroke="#ababab"
  5565.                             stroke-width="1.5"
  5566.                             stroke-linecap="round"
  5567.                             stroke-linejoin="round"
  5568.                         />
  5569.                     </g>
  5570.                 </svg>
  5571.                     `,
  5572.                 "Assign Priority",
  5573.                 () => {
  5574.                     // Check if the dropdown is already visible and remove it
  5575.                     const existingDropdown = document.querySelector('.custom-dropdown');
  5576.                     if (existingDropdown) {
  5577.                         existingDropdown.remove();
  5578.                         return; // Don't create a new dropdown if one is already visible
  5579.                     }
  5580.  
  5581.                     // Create the custom dropdown for priority options
  5582.                     let dropdown = document.createElement('div');
  5583.                     dropdown.className = 'custom-dropdown';
  5584.                     dropdown.style.position = 'absolute';
  5585.                     dropdown.style.background = 'white';
  5586.                     dropdown.style.border = '1px solid #ddd';
  5587.                     dropdown.style.padding = '5px';
  5588.                     dropdown.style.zIndex = '1000';
  5589.                     dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  5590.                     dropdown.style.maxHeight = '200px';
  5591.                     dropdown.style.overflowY = 'auto';
  5592.                     dropdown.style.minWidth = '200px';
  5593.  
  5594.                     // Define the priority options
  5595.                     const priorities = {
  5596.                         urgent: "Urgent",
  5597.                         high: "High",
  5598.                         normal: "Normal",
  5599.                         low: "Low"
  5600.                     };
  5601.  
  5602.                     // Create the dropdown options
  5603.                     Object.keys(priorities).forEach(priority => {
  5604.                         const option = document.createElement('div');
  5605.                         option.textContent = priorities[priority];
  5606.                         option.style.padding = '5px 10px';
  5607.                         option.style.cursor = 'pointer';
  5608.                         option.style.backgroundColor = 'white';
  5609.  
  5610.                         // Hover effect for the dropdown items
  5611.                         option.addEventListener('mouseover', () => {
  5612.                             option.style.backgroundColor = '#f1f1f1';
  5613.                         });
  5614.                         option.addEventListener('mouseout', () => {
  5615.                             option.style.backgroundColor = 'white';
  5616.                         });
  5617.  
  5618.                         // When an option is selected, update the flag color
  5619.                         option.addEventListener('click', () => {
  5620.                             selectedPriority = priority;
  5621.                             const priorityIconPath = document.getElementById('priority-icon-path-add');
  5622.                             const priorityIconExc = document.getElementById('priority-iconborder-add');
  5623.                             const priorityOutline = document.getElementById('priority-icon-exclamation-add');
  5624.  
  5625.  
  5626.                             // Define color changes for different priorities
  5627.                             const colors = {
  5628.                                 urgent: "red",
  5629.                                 high: "gold",
  5630.                                 normal: "transparent",
  5631.                                 low: "grey"
  5632.                             };
  5633.  
  5634.                             // Change the color of the flag icon based on selected priority
  5635.                             if (selectedPriority !== "none") {
  5636.                                 priorityIconPath.setAttribute('fill', colors[selectedPriority]);
  5637.                                 priorityIconPath.setAttribute('stroke',colors[selectedPriority]);
  5638.                                 if (colors[selectedPriority] == "red" )
  5639.                                 {
  5640.                                     priorityIconExc.setAttribute('stroke', 'white');
  5641.                                     priorityOutline.setAttribute('stroke', 'white');
  5642.                                 }
  5643.                                 else if (colors[selectedPriority] == "transparent"){
  5644.                                     priorityOutline.setAttribute('stroke', 'grey');
  5645.                                     priorityIconPath.setAttribute('stroke', 'grey');
  5646.                                 }
  5647.                                 else{
  5648.                                     priorityIconExc.setAttribute('stroke', 'black');
  5649.                                     priorityOutline.setAttribute('stroke', 'black');
  5650.                                 }
  5651.                                
  5652.                             }
  5653.  
  5654.                             // Remove the dropdown after selection
  5655.                             dropdown.remove();
  5656.                         });
  5657.  
  5658.                         dropdown.appendChild(option);
  5659.                     });
  5660.  
  5661.                     // Create a "Clear" button as part of the dropdown
  5662.                     const clearButton = document.createElement('button');
  5663.                     clearButton.textContent = 'Clear';
  5664.                     clearButton.style.padding = '5px 10px';
  5665.                     clearButton.style.marginTop = '10px';
  5666.                     clearButton.style.cursor = 'pointer';
  5667.                     clearButton.style.border = 'none';
  5668.                     clearButton.style.background = "lightgrey";
  5669.  
  5670.                     // When the "Clear" button is clicked, reset to original state
  5671.                     clearButton.addEventListener('click', () => {
  5672.                         const priorityIconPath = document.getElementById('priority-icon-path');
  5673.                         priorityIconPath.setAttribute('fill', 'none');
  5674.                         priorityIconPath.setAttribute('stroke', '#ababab');
  5675.                        
  5676.                         // Remove the dropdown after clicking "Clear"
  5677.                         dropdown.remove();
  5678.                     });
  5679.  
  5680.                     dropdown.appendChild(clearButton);
  5681.  
  5682.                     // Position the dropdown below the icon
  5683.                     const rect = priorityIcon.getBoundingClientRect();
  5684.                     const zoomFactor = 1; // Optional zoom adjustment
  5685.  
  5686.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  5687.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  5688.  
  5689.                     document.body.appendChild(dropdown);
  5690.                     const handleClickOutside = (event) => {
  5691.                         if (!priorityIcon.contains(event.target)) {
  5692.                             dropdown.remove();
  5693.                             document.removeEventListener('click', handleClickOutside);
  5694.                         }
  5695.                     };
  5696.                     document.addEventListener('click', handleClickOutside);
  5697.  
  5698.                 }
  5699.             );
  5700.  
  5701.            
  5702.             const taskIcon = createIconButton(
  5703.                 `<svg width="30px" height="30px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#000000">
  5704.  
  5705.                 <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5706.  
  5707.                 <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5708.  
  5709.                 <g id="SVGRepo_iconCarrier"> <path color="#000000" d="M7.992 0A2.008 2.008 0 0 0 6 2H5c-.657 0-1.178.06-1.617.225-.439.164-.79.461-.998.838-.415.752-.37 1.673-.385 2.931v5.012c.015 1.258-.03 2.179.385 2.932.208.376.56.673.998.838.439.164.96.224 1.617.224h3.133c.021-.05.031-.102.059-.15l.482-.85H5c-.592 0-1.006-.063-1.265-.16-.26-.098-.372-.203-.473-.387C3.06 13.087 3.015 12.259 3 11V6c.015-1.259.06-2.087.262-2.453.101-.184.213-.29.473-.387C3.995 3.062 4.408 3 5 3v.999h6V3c.593 0 1.006.063 1.266.16.26.098.371.203.472.387.202.366.247 1.194.262 2.453v2.832c.31.115.582.323.752.62v.001l.248.438V5.994c-.015-1.258.031-2.179-.385-2.932a1.88 1.88 0 0 0-.998-.837C12.179 2.06 11.657 2 11 2H9.996a2.008 2.008 0 0 0-1.992-2zm.01 1c.559 0 1 .442 1 1a.99.99 0 0 1-1 1 .982.982 0 0 1-.922-.61A1.01 1.01 0 0 1 7.003 2c0-.558.441-1 1-1zM5 6v1h6.012V6zm0 2v1h6.012V8zm-.01 2v1h3v-1z" fill="gray" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal;marker:none" white-space="normal"/> <path class="warning" color="#000000" d="M12.48 9.729a.443.443 0 0 0-.36.22l-3.061 5.397a.437.437 0 0 0 .379.654h6.125a.437.437 0 0 0 .379-.654l-3.059-5.397a.442.442 0 0 0-.402-.22zM12 11h1v.168c0 .348-.016.667-.047.957-.03.29-.069.581-.115.875h-.666a12.898 12.898 0 0 1-.125-.875 9.146 9.146 0 0 1-.047-.957zm.5 3a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1z" fill="#ababab" fill-rule="evenodd" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal" white-space="normal"/> </g>
  5710.  
  5711.                 </svg>`,
  5712.                 "Select Type", // Default text on the button
  5713.                 () => {
  5714.                     // Check if the dropdown is already visible and remove it
  5715.                     const existingDropdown = document.querySelector('.custom-dropdown');
  5716.                     if (existingDropdown) {
  5717.                         existingDropdown.remove();
  5718.                         return; // Don't create a new dropdown if one is already visible
  5719.                     }
  5720.  
  5721.                     // Create the dropdown container
  5722.                     let dropdown = document.createElement('div');
  5723.                     dropdown.className = 'custom-dropdown';
  5724.                                 dropdown.style.position = 'absolute';
  5725.                                 dropdown.style.background = 'white';
  5726.                                 dropdown.style.border = 'none';
  5727.                                 dropdown.style.padding = '4px 0';
  5728.                                 dropdown.style.zIndex = '1000';
  5729.                                 dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  5730.                                 dropdown.style.maxHeight = '200px';
  5731.                                 dropdown.style.overflowY = 'auto';
  5732.                                 dropdown.style.minWidth = '200px';
  5733.                                 dropdown.style.borderRadius = '8px';
  5734.  
  5735.                     // Define the options for Task/Checkpoint
  5736.                     const options = [
  5737.                         {
  5738.                             title: "Task",
  5739.                             icon: `<svg width="24px" height="24px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#000000">
  5740.  
  5741.                             <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5742.  
  5743.                             <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5744.  
  5745.                             <g id="SVGRepo_iconCarrier"> <path color="#000000" d="M7.992 0A2.008 2.008 0 0 0 6 2H5c-.657 0-1.178.06-1.617.225-.439.164-.79.461-.998.838-.415.752-.37 1.673-.385 2.931v5.012c.015 1.258-.03 2.179.385 2.932.208.376.56.673.998.838.439.164.96.224 1.617.224h3.133c.021-.05.031-.102.059-.15l.482-.85H5c-.592 0-1.006-.063-1.265-.16-.26-.098-.372-.203-.473-.387C3.06 13.087 3.015 12.259 3 11V6c.015-1.259.06-2.087.262-2.453.101-.184.213-.29.473-.387C3.995 3.062 4.408 3 5 3v.999h6V3c.593 0 1.006.063 1.266.16.26.098.371.203.472.387.202.366.247 1.194.262 2.453v2.832c.31.115.582.323.752.62v.001l.248.438V5.994c-.015-1.258.031-2.179-.385-2.932a1.88 1.88 0 0 0-.998-.837C12.179 2.06 11.657 2 11 2H9.996a2.008 2.008 0 0 0-1.992-2zm.01 1c.559 0 1 .442 1 1a.99.99 0 0 1-1 1 .982.982 0 0 1-.922-.61A1.01 1.01 0 0 1 7.003 2c0-.558.441-1 1-1zM5 6v1h6.012V6zm0 2v1h6.012V8zm-.01 2v1h3v-1z" fill="gray" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal;marker:none" white-space="normal"/> <path class="warning" color="#000000" d="M12.48 9.729a.443.443 0 0 0-.36.22l-3.061 5.397a.437.437 0 0 0 .379.654h6.125a.437.437 0 0 0 .379-.654l-3.059-5.397a.442.442 0 0 0-.402-.22zM12 11h1v.168c0 .348-.016.667-.047.957-.03.29-.069.581-.115.875h-.666a12.898 12.898 0 0 1-.125-.875 9.146 9.146 0 0 1-.047-.957zm.5 3a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1z" fill="#ababab" fill-rule="evenodd" font-family="sans-serif" font-weight="400" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;isolation:auto;mix-blend-mode:normal" white-space="normal"/> </g>
  5746.  
  5747.                             </svg>`
  5748.                         },
  5749.                         {
  5750.                             title: "Checkpoint",
  5751.                             icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16" fill="#000000">
  5752.  
  5753.                             <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5754.  
  5755.                             <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5756.  
  5757.                             <g id="SVGRepo_iconCarrier"> <path fill="#ababab" fill-rule="evenodd" d="M4,4 L9,4 C9.55228,4 10,3.55228 10,3 C10,2.44772 9.55228,2 9,2 L4,2 C2.89543,2 2,2.89543 2,4 L2,12 C2,13.1046 2.89543,14 4,14 L12,14 C13.1046,14 14,13.1046 14,12 L14,10 C14,9.44771 13.5523,9 13,9 C12.4477,9 12,9.44771 12,10 L12,12 L4,12 L4,4 Z M15.2071,2.29289 C14.8166,1.90237 14.1834,1.90237 13.7929,2.29289 L8.5,7.58579 L7.70711,6.79289 C7.31658,6.40237 6.68342,6.40237 6.29289,6.79289 C5.90237,7.18342 5.90237,7.81658 6.29289,8.20711 L7.79289,9.70711 C7.98043,9.89464 8.23478,10 8.5,10 C8.76522,10 9.01957,9.89464 9.20711,9.70711 L15.2071,3.70711 C15.5976,3.31658 15.5976,2.68342 15.2071,2.29289 Z"/> </g>
  5758.  
  5759.                             </svg>`
  5760.                         },
  5761.                     ];
  5762.  
  5763.                     // Create dropdown options
  5764.                     options.forEach(option => {
  5765.                         const item = document.createElement('div');
  5766.                         item.style.cursor = 'pointer';
  5767.                         item.style.padding = '8px 10px';
  5768.                         item.style.backgroundColor = 'white';
  5769.                         item.style.display ="flex";
  5770.                         item.style.flexDirection ="row";
  5771.                         item.style.gap = "8px"
  5772.                        
  5773.                         item.innerHTML = `${option.icon} ${option.title}`;
  5774.                        
  5775.                         // Add click handler to set the button text and close the dropdown
  5776.                         item.addEventListener('click', () => {
  5777.                             selectedOption = option.title;
  5778.                             taskIcon.innerHTML = option.icon; // Update button text
  5779.                             dropdown.remove(); // Close the dropdown
  5780.                         });
  5781.  
  5782.                         dropdown.appendChild(item);
  5783.                     });
  5784.  
  5785.                     // Append the dropdown to the button's position
  5786.                     taskIcon.appendChild(dropdown);
  5787.                     const rect = taskIcon.getBoundingClientRect();
  5788.                     const zoomFactor = 1; // Optional zoom adjustment
  5789.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  5790.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  5791.                     document.body.appendChild(dropdown);
  5792.                     const handleClickOutside = (event) => {
  5793.                         if (!taskIcon.contains(event.target)) {
  5794.                             dropdown.remove();
  5795.                             document.removeEventListener('click', handleClickOutside);
  5796.                         }
  5797.                     };
  5798.                     document.addEventListener('click', handleClickOutside);
  5799.                 }
  5800.             );
  5801.            
  5802.  
  5803.             const bountyIcon = createIconButton(
  5804.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512" fill="#000000">
  5805.                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5806.                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5807.                     <g id="SVGRepo_iconCarrier">
  5808.                     <title>ionicons-v5-p</title>
  5809.                     <circle cx="256" cy="160" r="128" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5810.                     <path d="M143.65,227.82,48,400l86.86-.42a16,16,0,0,1,13.82,7.8L192,480l88.33-194.32" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5811.                     <path d="M366.54,224,464,400l-86.86-.42a16,16,0,0,0-13.82,7.8L320,480,256,339.2" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5812.                     <circle cx="256" cy="160" r="64" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5813.                     </g>
  5814.                     </svg>`,
  5815.                     "Assign Bounties",  
  5816.                     () => {
  5817.                         // If the current element is an input field, save the value and revert to the text
  5818.                         const container = document.createElement('div');
  5819.                         container.classList.add('bounty-container');
  5820.                         container.style.display = 'inline-flex';
  5821.                         container.style.alignItems = 'center';  // Align items vertically centered
  5822.                         container.style.gap = '5px';  // Small gap between icon and input
  5823.                         container.style.width = '35px';  // Fixed width for the container
  5824.                
  5825.                         // Create input field if clicking on the current text
  5826.                         const inputField = document.createElement('input');
  5827.                         inputField.type = 'text';
  5828.                         inputField.className = 'bounty-input';
  5829.                         inputField.value = currentValue;  // Set the current value in the input
  5830.                         inputField.style.width = '35px';  // Match the width
  5831.                         inputField.style.padding = '5px';
  5832.                         inputField.style.fontSize = '16px';
  5833.                         inputField.style.textAlign = 'center';
  5834.                         inputField.style.border = '1px solid #ababab';
  5835.                         inputField.style.borderRadius = '4px';
  5836.                         inputField.style.backgroundColor = 'transparent';  // Keep background transparent
  5837.                         inputField.style.color = '#ababab';  // Match the SVG color
  5838.                
  5839.                         // Append the input field into the container
  5840.                         container.appendChild(inputField);
  5841.                
  5842.                         // Replace the SVG or text with the container holding the input field
  5843.                         bountyIcon.innerHTML = '';
  5844.                         bountyIcon.appendChild(container);
  5845.                
  5846.                         // Focus the input field when it's displayed
  5847.                         inputField.focus();
  5848.                         const value = inputField.value.trim();  // Get the trimmed value
  5849.                             if (value) {
  5850.                                 currentValue = value;  // Save the value entered by the user
  5851.                                 currentHtml = value;}
  5852.                         // When the user finishes editing (on blur), save the value and update the display
  5853.                         inputField.addEventListener('blur', function () {
  5854.                             const value = inputField.value.trim();  // Get the trimmed value
  5855.                
  5856.                             // If the input is not empty, save the new value
  5857.                             if (value) {
  5858.                                 currentValue = value;  // Save the value entered by the user
  5859.                                 currentHtml = value;
  5860.                             }
  5861.                             else {
  5862.                                 currentValue = "";
  5863.                                 currentHtml = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512" fill="#000000">
  5864.                         <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5865.                         <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5866.                         <g id="SVGRepo_iconCarrier">
  5867.                         <title>ionicons-v5-p</title>
  5868.                         <circle cx="256" cy="160" r="128" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5869.                         <path d="M143.65,227.82,48,400l86.86-.42a16,16,0,0,1,13.82,7.8L192,480l88.33-194.32" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5870.                         <path d="M366.54,224,464,400l-86.86-.42a16,16,0,0,0-13.82,7.8L320,480,256,339.2" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5871.                         <circle cx="256" cy="160" r="64" style="fill:none;stroke:#ababab;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
  5872.                         </g>
  5873.                     </svg>`
  5874.                             }
  5875.                
  5876.                             // Revert the icon to show the current value (either new or original)
  5877.                             bountyIcon.innerHTML = currentHtml;
  5878.                             bountyIcon.style.width = "35px";
  5879.                             bountyIcon.style.minWidth = "35px";
  5880.                             bountyIcon.style.color =  '#ababab';
  5881.                         });
  5882.                     }
  5883.             );
  5884.            
  5885.             const assignIcon = createIconButton(
  5886.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  5887.                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  5888.                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  5889.                     <g id="SVGRepo_iconCarrier">
  5890.                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" fill="#ABABAB"/>
  5891.                     </g>
  5892.                 </svg>`,
  5893.                 "Select Assignee",
  5894.                 () => {
  5895.                     // Check if the dropdown is already visible and remove it
  5896.                     const existingDropdown = document.querySelector('.custom-dropdown');
  5897.                     if (existingDropdown) {
  5898.                         existingDropdown.remove();
  5899.                         return;
  5900.                     }
  5901.            
  5902.                     // Create the custom dropdown for team members
  5903.                     let dropdown = document.createElement('div');
  5904.                     dropdown.className = 'custom-dropdown';
  5905.                     dropdown.style.position = 'absolute';
  5906.                     dropdown.style.background = 'white';
  5907.                     dropdown.style.border = '1px solid #ddd';
  5908.                     dropdown.style.borderRadius = '4px';
  5909.                     dropdown.style.padding = '0';
  5910.                     dropdown.style.zIndex = '1000';
  5911.                     dropdown.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
  5912.                     dropdown.style.maxHeight = '300px';
  5913.                     dropdown.style.overflowY = 'auto';
  5914.            
  5915.                     // Add search input to filter the team members
  5916.                     let searchInputWrapper = document.createElement('div');
  5917.                     searchInputWrapper.classList.add('search-input-wrapper')
  5918.                     searchInputWrapper.style.width = '100%';
  5919.                     searchInputWrapper.style.padding = '10px';
  5920.                     let searchInput = document.createElement('input');
  5921.                     searchInput.type = 'text';
  5922.                     searchInput.placeholder = 'Search team members';
  5923.                     searchInput.style.width = '90%';
  5924.                     searchInput.style.padding = '5px';
  5925.                     searchInput.style.margin = '10px';
  5926.                     searchInput.style.border = '1px solid #ddd';
  5927.                     searchInput.style.borderRadius = '4px';
  5928.                     searchInput.style.boxSizing = 'border-box';
  5929.                     searchInput.id='searchInput'
  5930.                     // searchInputWrapper.appendChild(searchInput)
  5931.                     // Append search input to the dropdown
  5932.                     dropdown.appendChild(searchInput);
  5933.            
  5934.                     // Container for member list
  5935.                     let memberList = document.createElement('div');
  5936.                     dropdown.appendChild(memberList);
  5937.            
  5938.                     // Populate dropdown with team members
  5939.                     team_members.forEach(member => {
  5940.                         const memberItem = document.createElement('div');
  5941.                         memberItem.textContent = member.name;
  5942.                         memberItem.style.padding = '5px 10px';
  5943.                         memberItem.style.cursor = 'pointer';
  5944.                         memberItem.style.backgroundColor = 'white';
  5945.            
  5946.                         // Hover effect for the dropdown items
  5947.                         memberItem.addEventListener('mouseover', () => {
  5948.                             memberItem.style.backgroundColor = '#f1f1f1';
  5949.                         });
  5950.                         memberItem.addEventListener('mouseout', () => {
  5951.                             memberItem.style.backgroundColor = 'white';
  5952.                         });
  5953.            
  5954.                         // When a member is selected
  5955.                         memberItem.addEventListener('click', () => {
  5956.                             const initials = getInitials(member.name);
  5957.                             createInitialsCircle(initials, member.name); // Replace with initials circle
  5958.                             selectedMember = member.name;
  5959.                             selectedMemberData = {"id":member.id,"name":member.name};
  5960.                             dropdown.remove(); // Remove the dropdown
  5961.                         });
  5962.            
  5963.                         memberList.appendChild(memberItem);
  5964.                     });
  5965.            
  5966.                     // Position the dropdown below the icon
  5967.                     const rect = assignIcon.getBoundingClientRect();
  5968.                     const zoomFactor = 1; // Get the zoom level
  5969.            
  5970.                     dropdown.style.left = `${rect.left / zoomFactor}px`; // Adjust for zoom level
  5971.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`; // Adjust for zoom level and page scroll
  5972.            
  5973.                     document.body.appendChild(dropdown);
  5974.  
  5975.                     const handleClickOutside = (event) => {
  5976.                         if (!assignIcon.contains(event.target) && !(event.target.id == "searchInput")) {
  5977.                             dropdown.remove();
  5978.                             document.removeEventListener('click', handleClickOutside);
  5979.                         }
  5980.                     };
  5981.                     document.addEventListener('click', handleClickOutside);
  5982.  
  5983.            
  5984.                     // Search functionality
  5985.                     searchInput.addEventListener('input', function () {
  5986.                         const query = searchInput.value.toLowerCase();
  5987.                         const items = memberList.querySelectorAll('div');
  5988.                         items.forEach(item => {
  5989.                             const text = item.textContent.toLowerCase();
  5990.                             if (text.indexOf(query) === -1) {
  5991.                                 item.style.display = 'none';
  5992.                             } else {
  5993.                                 item.style.display = 'block';
  5994.                             }
  5995.                         });
  5996.                     });
  5997.            
  5998.                     // Clear button functionality
  5999.                     const clearButton = document.createElement('button');
  6000.                     clearButton.textContent = 'Clear';
  6001.                     clearButton.style.padding = '5px 10px';
  6002.                     clearButton.style.margin = '10px';
  6003.                     clearButton.style.cursor = 'pointer';
  6004.                     clearButton.style.border = 'none';
  6005.                     clearButton.style.borderRadius = '4px';
  6006.                     clearButton.style.fontSize = '14px';
  6007.                     clearButton.style.background = "lightgrey";
  6008.            
  6009.                     clearButton.addEventListener('click', () => {
  6010.                         selectedMember = 'none'; // Set selected member to "none"
  6011.                         selectedMemberData = {};
  6012.                         assignIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  6013.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  6014.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  6015.                                                     <g id="SVGRepo_iconCarrier">
  6016.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" fill="#ABABAB"/>
  6017.                                                     </g>
  6018.                                                 </svg>`; // Reset to the original SVG
  6019.                         dropdown.remove();
  6020.                     });
  6021.                    
  6022.                     dropdown.appendChild(clearButton);
  6023.                    
  6024.                 }
  6025.             );
  6026.            
  6027.  
  6028.             function getInitials(username) {
  6029.                 const nameParts = username.trim().split(/\s+/);
  6030.                 return nameParts.map(part => part[0].toUpperCase()).join('');
  6031.             }
  6032.  
  6033.             function createInitialsCircle(initials, username) {
  6034.                 // Create the circle element for initials
  6035.                 const circle = document.createElement('div');
  6036.                 circle.className = 'initials-circle';
  6037.                 circle.style.width = '25px';
  6038.                 circle.style.height = '25px';
  6039.                 circle.style.borderRadius = '50%';
  6040.                 circle.style.display = 'flex';
  6041.                 circle.style.alignItems = 'center';
  6042.                 circle.style.justifyContent = 'center';
  6043.                 circle.style.backgroundColor = '#7c4dff';
  6044.                 circle.style.color = '#fff';
  6045.                 circle.style.cursor = 'pointer';
  6046.                 circle.style.fontSize = '14px';
  6047.                 circle.textContent = initials;
  6048.  
  6049.                 // Replace the assign icon with the circle containing the initials
  6050.                 assignIcon.innerHTML = '';  // Clear previous icon
  6051.                 assignIcon.appendChild(circle);
  6052.                
  6053.                
  6054.                 assignIcon.title = username;
  6055.  
  6056.                 // When the circle is clicked, open the dropdown again
  6057.                 circle.addEventListener('click', () => {
  6058.                     createIconButton(assignIcon.innerHTML, "Assign", () => {
  6059.                         openDropdown();
  6060.                     });
  6061.                 });
  6062.             }
  6063.  
  6064.            // Create the date icon button (SVG for the calendar)
  6065.            
  6066.             const dateIcon = createIconButton(
  6067.                 `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  6068.                     <g id="SVGRepo_iconCarrier">
  6069.                         <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  6070.                     </g>
  6071.                 </svg>`,
  6072.                 "Select Date",
  6073.                 () => {
  6074.                     // Check if the date picker is already visible and remove it
  6075.                     const existingDropdown = document.querySelector('.date-picker-dropdown');
  6076.                     if (existingDropdown) {
  6077.                         existingDropdown.remove();
  6078.                         return; // Don't create a new dropdown if one is already visible
  6079.                     }
  6080.                
  6081.                     // Create the date input field (it will appear as a dropdown)
  6082.                     const dateInput = document.createElement('input');
  6083.                     dateInput.type = 'date';
  6084.                     dateInput.className = 'date-icon-input'; // Add class for styling
  6085.                
  6086.                     // Create a dropdown container for the date input field
  6087.                     const dropdown = document.createElement('div');
  6088.                     dropdown.classList.add('date-picker-dropdown', 'input-style');
  6089.                     dropdown.style.position = 'absolute';
  6090.                     dropdown.style.zIndex = '9999';  
  6091.                     dropdown.style.width = "200px";
  6092.                     const rect = dateIcon.getBoundingClientRect();
  6093.                     const zoomFactor = 1;
  6094.                
  6095.                     dropdown.style.left = `${rect.left / zoomFactor}px`;
  6096.                     dropdown.style.top = `${(rect.bottom + window.scrollY) / zoomFactor}px`;
  6097.                
  6098.                     dropdown.appendChild(dateInput);
  6099.                
  6100.                     // Create a "Clear" button in the next row
  6101.                     const clearButton = document.createElement('button');
  6102.                     clearButton.textContent = 'Clear';
  6103.                     clearButton.classList.add('clear-button');
  6104.                     clearButton.style.marginTop = '10px';
  6105.                     clearButton.style.padding = '5px 10px';
  6106.                     clearButton.style.cursor = 'pointer';
  6107.                     clearButton.style.backgroundColor = '#f0f0f0';
  6108.                     clearButton.style.border = '1px solid #ddd';
  6109.                     clearButton.style.borderRadius = '4px';
  6110.                     clearButton.style.fontSize = '14px';
  6111.                
  6112.                     // When the "Clear" button is clicked, reset the input and icon
  6113.                     clearButton.addEventListener('click', () => {
  6114.                         dateInput.value = ''; // Reset the date input
  6115.                         dateIcon.style.width = "35px";
  6116.                         dateIcon.style.minWidth = "35px";
  6117.                         dateIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none">
  6118.                     <g id="SVGRepo_iconCarrier">
  6119.                         <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  6120.                     </g>
  6121.                 </svg>`; // Reset the date icon text
  6122.                         dropdown.remove(); // Remove the dropdown
  6123.                     });
  6124.                
  6125.                     dropdown.appendChild(clearButton);
  6126.                
  6127.                     // Append the dropdown to the body
  6128.                     document.body.appendChild(dropdown);
  6129.                
  6130.                     const handleClickOutside = (event) => {
  6131.                         if (!dateIcon.contains(event.target) && !dateInput.contains(event.target)) {
  6132.                             dropdown.remove();
  6133.                             document.removeEventListener('click', handleClickOutside);
  6134.                         }
  6135.                     };
  6136.                     document.addEventListener('click', handleClickOutside);
  6137.                     // When a date is selected, update the icon HTML with the selected date
  6138.                     dateInput.addEventListener('change', function () {
  6139.                         selectedDate = new Date(this.value);
  6140.                         const formattedDate = selectedDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: '2-digit' });
  6141.                        
  6142.                         // Update the icon's HTML with the selected date
  6143.                         dateIcon.innerHTML = `${formattedDate}`;
  6144.                         dateIcon.offsetWidth;  
  6145.                         dateIcon.style.width = "auto";
  6146.                         dateIcon.style.minWidth = "100px";  // Adjust this as per your needs
  6147.                         // Hide the dropdown after date selection
  6148.                         dropdown.remove();
  6149.                     });
  6150.                 }
  6151.             );
  6152.  
  6153.            
  6154.             const saveButton = document.createElement('button');
  6155.             saveButton.className = "save-button";
  6156.             saveButton.textContent = "Save";
  6157.             saveButton.style.margin = "0px 10px";
  6158.             saveButton.title = "Save Task";
  6159.  
  6160.             function handleKeydown(event) {
  6161.                
  6162.                 if (event.key === 'Enter' && rowIsOpen) {
  6163.                     event.preventDefault();
  6164.                     saveData();
  6165.                 }
  6166.             }
  6167.             const saveData = () => {
  6168.                
  6169.                 const data = {
  6170.                     "priority": selectedPriority,
  6171.                     "member": selectedMemberData, // format: {id: some id, name: some name}
  6172.                     "date": selectedDate,
  6173.                     "bounty": currentValue,
  6174.                     "type": selectedOption,
  6175.                     "name": taskInput.value
  6176.                 };
  6177.                 selectedPriority = "";
  6178.                 selectedDate = "";
  6179.                 selectedOption = "";
  6180.                 selectedMember = "";
  6181.                 selectedMemberData = {};
  6182.                 currentValue = "";
  6183.                 taskInput.value = "";
  6184.                
  6185.                 addTask(button, data,handleKeydown);
  6186.                
  6187.                 addTaskTr.classList.remove('hidden')
  6188.             };
  6189.  
  6190.             // Add event listener to save button
  6191.             saveButton.addEventListener('click', saveData);
  6192.            
  6193.             document.addEventListener('keydown', handleKeydown);
  6194.             const cancelButton = document.createElement('button');
  6195.             cancelButton.className = "cancel-button";
  6196.             cancelButton.textContent = "Cancel";
  6197.             cancelButton.title = "Cancel";
  6198.            
  6199.             cancelButton.addEventListener('click', () => {
  6200.                 const rowToRemove = cancelButton.closest('tr');  
  6201.                 if (rowToRemove) {
  6202.                     rowToRemove.remove();
  6203.                     rowIsOpen = false;
  6204.                     document.removeEventListener('keydown', handleKeydown);
  6205.                 }
  6206.                 addTaskTr.classList.remove('hidden')
  6207.             });
  6208.             newCell.appendChild(taskInput);
  6209.             newRow.appendChild(newCell);
  6210.  
  6211.             iconBtnWrapper.append(taskIcon, assignIcon, priorityIcon, bountyIcon, dateIcon);
  6212.             newCell2.append(iconBtnWrapper);
  6213.             newCell3.append(saveButton, cancelButton);
  6214.             newRow.appendChild(newCell2);
  6215.             newRow.appendChild(newCell3);
  6216.        
  6217.             addTaskRow.insertAdjacentElement('beforebegin', newRow);
  6218.             taskInput.focus();
  6219.             enforceTableCellHeight(35);
  6220.  
  6221.         }
  6222.         const priorityMapping = {
  6223.             urgent: {
  6224.                 icon: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  6225.                             <g id="SVGRepo_iconCarrier">
  6226.                                 <path
  6227.                                     id="priority-icon-path"
  6228.                                     d="M12 4L20 20H4L12 4Z"
  6229.                                     fill="red" stroke="red" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6230.                                 <path d="M12 8L12 12" id="priority-icon-exclamation" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
  6231.                                 <path id="priority-icon-border" d="M12 16.01L12.01 15.9989" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
  6232.                             </g>
  6233.                         </svg>`,
  6234.                 color: "red",
  6235.                 stroke: "red"
  6236.             },
  6237.             high: {
  6238.                 icon: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  6239.                             <g id="SVGRepo_iconCarrier">
  6240.                                 <path
  6241.                                     id="priority-icon-path"
  6242.                                     d="M12 4L20 20H4L12 4Z"
  6243.                                     fill="gold" stroke="gold" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6244.                                 <path d="M12 8L12 12" id="priority-icon-exclamation" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6245.                                 <path id="priority-icon-border" d="M12 16.01L12.01 15.9989" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6246.                             </g>
  6247.                         </svg>`,
  6248.                 color: "gold",
  6249.                 stroke: "black"
  6250.             },
  6251.             normal: {
  6252.                 icon: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  6253.                             <g id="SVGRepo_iconCarrier">
  6254.                                 <path
  6255.                                     id="priority-icon-path"
  6256.                                     d="M12 4L20 20H4L12 4Z"
  6257.                                     fill="transparent" stroke="grey" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6258.                                 <path d="M12 8L12 12" id="priority-icon-exclamation" stroke="grey" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6259.                                 <path id="priority-icon-border" d="M12 16.01L12.01 15.9989" stroke="grey" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6260.                             </g>
  6261.                         </svg>`,
  6262.                 color: "blue",
  6263.                 stroke: "white"
  6264.             },
  6265.             low: {
  6266.                 icon: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  6267.                             <g id="SVGRepo_iconCarrier">
  6268.                                 <path
  6269.                                     id="priority-icon-path"
  6270.                                     d="M12 4L20 20H4L12 4Z"
  6271.                                     fill="grey" stroke="grey" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6272.                                 <path d="M12 8L12 12" id="priority-icon-exclamation" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6273.                                 <path id="priority-icon-border" d="M12 16.01L12.01 15.9989" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
  6274.                             </g>
  6275.                         </svg>`,
  6276.                 color: "grey",
  6277.                 stroke: "white"
  6278.             }
  6279.         };
  6280.  
  6281.      
  6282.         async function addTask(button,data,handleKeydown) {
  6283.            
  6284.             //gett the nearest table
  6285.             const milestoneSection = button.closest('table');
  6286.             const milestoneHeader = milestoneSection.querySelector('thead tr th:first-child');
  6287.             const milestoneText = milestoneHeader ? milestoneHeader.textContent.trim() : null;
  6288.             const milestoneSectionInput = button.closest('tr');
  6289.             // input for addtask
  6290.             const taskInput = data.name;
  6291.             const assigneeInput = data.member.id;
  6292.             const dateInput = data.date;
  6293.             const bountyInput = data.bounty;
  6294.             const checkpointCheckbox = data.type == "Checkpoint";
  6295.             const selectedAssignee = data.member.name;
  6296.             const priorityText = data.priority;
  6297.            
  6298.  
  6299.             let { label, color } = { label: `<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24" fill="none">
  6300.                     <g id="SVGRepo_iconCarrier">
  6301.                         <path d="M19 2H5C3.9 2 3 2.9 3 4V20C3 21.1 3.9 22 5 22H19C20.1 22 21 21.1 21 20V4C21 2.9 20.1 2 19 2ZM19 20H5V8H19V20ZM5 4H7V6H5V4ZM19 4H17V6H19V4Z" fill="#ababab"/>
  6302.                     </g>
  6303.                 </svg>`, color: "black" }; // Initialize with default values
  6304.             if (dateInput) {
  6305.                 const formatted = `${dateInput.getFullYear()}-${String(dateInput.getMonth() + 1).padStart(2, '0')}-${String(dateInput.getDate()).padStart(2, '0')}`;
  6306.                 ({ label, color } = getDateLabelAndColor(formatted));
  6307.             }
  6308.            
  6309.             // validate the task name input
  6310.             if (!taskInput.trim()) {
  6311.                 alert("Please enter a valid task name.");
  6312.                 return;
  6313.             }
  6314.  
  6315.             let formattedDate = null;
  6316.             if (dateInput){
  6317.                 duedate = dateInput;
  6318.                 formattedDate = `${duedate.getFullYear()}-${String(duedate.getMonth() + 1).padStart(2, '0')}-${String(duedate.getDate()).padStart(2, '0')}`;
  6319.             }
  6320.             else{
  6321.                 formattedDate = null;
  6322.                 duedate = null;
  6323.             }
  6324.             //BACKEND Call
  6325.             const taskData = {
  6326.                 name: taskInput,
  6327.                 assignee: assigneeInput,
  6328.                 dueDate: formattedDate,
  6329.                 bounty: bountyInput,
  6330.                 isCheckpoint: checkpointCheckbox,
  6331.                 priority : priorityText,
  6332.                 project_ID: projectId,
  6333.                 milestone: milestoneText
  6334.             };
  6335.            
  6336.             const taskId = await saveTaskToBackend(taskData);
  6337.            
  6338.             taskFilterContainer.style.display = "block";
  6339.             noTasksMessage.style.display = "none";
  6340.  
  6341.             // create a new tr for task
  6342.             const newTaskRow = document.createElement('tr');
  6343.             newTaskRow.style.textAlign = 'left';
  6344.             newTaskRow.style.height = '40px';
  6345.             newTaskRow.classList.add("task-row");
  6346.             newTaskRow.id = taskId;
  6347.             newTaskRow.setAttribute('draggable', 'true');
  6348.             newTaskRow.setAttribute('ondragstart', 'drag(event)');
  6349.             newTaskRow.setAttribute('ondragover', 'allowDrop(event)');
  6350.             newTaskRow.setAttribute('ondrop', 'drop(event)');
  6351.             newTaskRow.setAttribute('data-status', 'I'); // Add initial status
  6352.             newTaskRow.setAttribute('value', 'I'); // Add initial value
  6353.             // set the inner html for task
  6354.             let priorityIcon = "";
  6355.             if (priorityText){
  6356.                 priorityIcon = priorityMapping[priorityText.toLowerCase()].icon;
  6357.             }
  6358.             else{
  6359.                 priorityIcon = priorityMapping['normal'].icon;
  6360.             }
  6361.            
  6362.             if (checkpointCheckbox) {
  6363.                 // create a single task for milestone check
  6364.                 let flagColor = "#DD1D43"; // Default red for past due
  6365.                 const today = new Date();
  6366.                 today.setHours(0, 0, 0, 0);
  6367.                
  6368.                 if (dateInput && new Date(dateInput) > today) {
  6369.                     flagColor = "grey"; // Grey for future due date
  6370.                 }
  6371.                 newTaskRow.innerHTML = `
  6372.                     <td class="task-row-elems">
  6373.                         <div class="task-row-title" style="display: flex; flex-direction: row; align-items: center; gap: 4px;">
  6374.                             <span class="flag-icon" style="display: inline-block; cursor:pointer; width: 20px; height: 20px; margin-left: 0px;">
  6375.                                 <svg onclick="updateFlag(this)" width="16" height="19" viewBox="0 0 16 19" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink: 0;">
  6376.                                     <path d="M0 19V0H16L14 5L16 10H2V19H0Z" fill="#DD1D43"/>
  6377.                                 </svg>
  6378.                             </span>
  6379.                             <span onclick="openTaskModal(${taskId})" id="task-name-${taskId}" class="task-name" style="padding-left: 10px;"> ${taskInput}</span>
  6380.                         </div>
  6381.                         <div style="display: flex; gap: 10px;">
  6382.                             <button title="Rename Task" onclick="editTask(${taskId})" class="edit-btn">
  6383.                                 <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
  6384.                                     <path d="M7.37333 4.01333L7.98667 4.62667L1.94667 10.6667H1.33333V10.0533L7.37333 4.01333ZM9.77333 0C9.60667 0 9.43333 0.0666666 9.30667 0.193333L8.08667 1.41333L10.5867 3.91333L11.8067 2.69333C12.0667 2.43333 12.0667 2.01333 11.8067 1.75333L10.2467 0.193333C10.1133 0.06 9.94667 0 9.77333 0ZM7.37333 2.12667L0 9.5V12H2.5L9.87333 4.62667L7.37333 2.12667Z" fill="#939CA3"/>
  6385.                                 </svg>
  6386.                             </button>
  6387.                             <button title="Delete Task" onclick="deleteTask(this,${taskId})" class="edit-btn">
  6388.                                 <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  6389.                                     <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  6390.                                 </svg>
  6391.                             </button>
  6392.                         </div>
  6393.                     </td>
  6394.                     <td style="border-left: 1px solid #CED4DA; padding-left: 10px;"></td>
  6395.                  <td class="assignee-input" style="border-left: 1px solid #CED4DA; padding-left: 10px; display: flex; justify-content: center; align-items: center;">
  6396.                         <button title="Assign Assignee" id="${taskId}" class="assign-btn" onclick="openAssigneeDropdown(${taskId},this)" style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6397.                             ${selectedAssignee ? `
  6398.                                 <div class="initials-circle" style="width: 25px; height: 25px; border-radius: 50%; display: flex; justify-content: center; align-items: center; background-color: #7c4dff; color: #fff; font-size: 14px; cursor: pointer;">
  6399.                                     ${getInitials(selectedAssignee)}
  6400.                                 </div>` : `
  6401.                                                                                 <svg class="assignee-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="width: 24px; height: 24px; fill: #ABABAB;">
  6402.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  6403.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  6404.                                                     <g id="SVGRepo_iconCarrier">
  6405.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" />
  6406.                                                     </g>
  6407.                                                 </svg>`
  6408.                             }
  6409.                         </button>
  6410.                     </td>
  6411.  
  6412.  
  6413.                     <td class="date-input" value="${duedate}" style=" justify-items:center; align-items: center;border-left: 1px solid #CED4DA; padding-left: 10px; color: ${color};">
  6414.                        <button title="Change Date" class="assign-btn"
  6415.                        {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  6416.                        onclick="openDueDateDropdown(${taskId},this)"
  6417.                        {% endif %}
  6418.                        style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6419.  
  6420.                         ${label}
  6421.                     </button>
  6422.                     </td>
  6423.                     <td class="priority-input" value="${priorityText}" title="${priorityText}"  style="border-left: 1px solid #CED4DA; padding-left: 10px; text-align: center; vertical-align: middle;justify-content: center; display:flex;">
  6424.                         <button title="Change Priority" class="assign-btn"
  6425.                        
  6426.                         onclick="openPriorityDropdown(${taskId},this)"
  6427.                        
  6428.                         style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6429.  
  6430.                         ${priorityIcon || '-' }
  6431.                         </button>
  6432.                     </td>
  6433.                     <td class="bountie-input" style="padding-left: 10px; justify-content: center; justify-items:center;">
  6434.                     <button title="Change Bounties"  id="${taskId}" value="${bountyInput || '1'}" class="assign-btn bounty-btn"
  6435.                     {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  6436.                     onclick="openBountyDropdown(${taskId},this)"
  6437.                     {% endif %}
  6438.                      style="justify-content: center;width:35px; border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6439.                     <div>${bountyInput || '-'}</div>
  6440.                     </button>
  6441.                 </td>
  6442.                    
  6443.                 `;
  6444.             } else {
  6445.                 newTaskRow.innerHTML = `
  6446.                                 <td class="task-row-elems">
  6447.                         <div class="" style="width: 100%; display: flex; flex-direction: row; align-items: center; gap: 4px; justify-content: space-between;">
  6448.                             <div class="task-row-title"><!-- Always add the checkbox for new tasks since they start with 0 subtasks -->
  6449.                             <label class="circular-checkbox">
  6450.                                 <input
  6451.                                     class="taskCheckbox"
  6452.                                     type="checkbox"
  6453.                                     onchange="updateTaskStatus(${taskId}, this)"
  6454.                                 >
  6455.                             </label>
  6456.  
  6457.                             <svg id="togglesvg" class="arrow-svg" onclick="toggleSubtask(this)" style="display:none; cursor: pointer;" width="8" height="20" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
  6458.                                 <path d="M1 9L5 5L1 1" stroke="#6D747A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
  6459.                             </svg>
  6460.                             <span id="togglespan" style="padding-left:8px;"></span>
  6461.                             <span onclick="openTaskModal(${taskId})" id="task-name-${taskId}"class="task-name" style="padding-left:10px;"> ${taskInput}</span>
  6462.                             </div>
  6463.                             <div style="display: flex; gap: 10px;">
  6464.                                         <button title="Add Subtask" onclick="addSubtaskRow(this, ${taskId})" class="edit-btn">
  6465.                                             <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  6466.                                                 <path d="M8 3V13M3 8H13" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  6467.                                             </svg>
  6468.                                         </button>
  6469.                                        
  6470.                                         <!-- Edit Icon to Rename Task -->
  6471.                                         <button title="Rename Task" onclick="editTask(${taskId})" class="edit-btn">
  6472.                                             <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
  6473.                                                 <path d="M7.37333 4.01333L7.98667 4.62667L1.94667 10.6667H1.33333V10.0533L7.37333 4.01333ZM9.77333 0C9.60667 0 9.43333 0.0666666 9.30667 0.193333L8.08667 1.41333L10.5867 3.91333L11.8067 2.69333C12.0667 2.43333 12.0667 2.01333 11.8067 1.75333L10.2467 0.193333C10.1133 0.06 9.94667 0 9.77333 0ZM7.37333 2.12667L0 9.5V12H2.5L9.87333 4.62667L7.37333 2.12667Z" fill="#939CA3"/>
  6474.                                                 </svg>
  6475.                                                
  6476.                                         </button>
  6477.                                         <button title="Delete Task" onclick="deleteTask(this,${taskId})" class="edit-btn">
  6478.                                         <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg">
  6479.                                             <path d="M3 3L13 13M3 13L13 3" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  6480.                                         </svg>
  6481.  
  6482.                                         </button>
  6483.                                     </div>
  6484.                             <span class="subtask-count"> (0) </span>
  6485.                         </div>
  6486.                     </td>
  6487.                     <td style="padding: 10px;">
  6488.                         <div style="display:none;" class="no-subtasks-message"> No subtasks </div>
  6489.                         <div class="status-bar-container" style="position: relative;">
  6490.                                         <div class="status-bar" style="width: 100%; height: 10px; background-color: lightgray;">
  6491.                                             <div class="status-bar-completed" style="height: 100%; background-color: green;"></div>
  6492.                                         </div>
  6493.                                         <div class="progress-tooltip">
  6494.                                             0 out of 0 tasks remaining
  6495.                                         </div>
  6496.                                     </div> </td>
  6497.                          <td class="assignee-input" style="border-left: 1px solid #CED4DA; padding-left: 10px; display: flex; justify-content: center; align-items: center;">
  6498.                         <button title="Assign Assignee"  id="${taskId}" class="assign-btn" onclick="openAssigneeDropdown(${taskId},this)" style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6499.                             ${selectedAssignee ? `
  6500.                                 <div class="initials-circle" style="width: 25px; height: 25px; border-radius: 50%; display: flex; justify-content: center; align-items: center; background-color: #7c4dff; color: #fff; font-size: 14px; cursor: pointer;">
  6501.                                     ${getInitials(selectedAssignee)}
  6502.                                 </div>` : `
  6503.                                 <svg class="assignee-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" style="width: 24px; height: 24px; fill: #ABABAB;">
  6504.                                                     <g id="SVGRepo_bgCarrier" stroke-width="0"/>
  6505.                                                     <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
  6506.                                                     <g id="SVGRepo_iconCarrier">
  6507.                                                         <path fill-rule="evenodd" clip-rule="evenodd" d="M3 18C3 15.3945 4.66081 13.1768 6.98156 12.348C7.61232 12.1227 8.29183 12 9 12C9.70817 12 10.3877 12.1227 11.0184 12.348C11.3611 12.4703 11.6893 12.623 12 12.8027C12.3107 12.623 12.6389 12.4703 12.9816 12.348C13.6123 12.1227 14.2918 12 15 12C15.7082 12 16.3877 12.1227 17.0184 12.348C19.3392 13.1768 21 15.3945 21 18V21H15.75V19.5H19.5V18C19.5 15.5147 17.4853 13.5 15 13.5C14.4029 13.5 13.833 13.6163 13.3116 13.8275C14.3568 14.9073 15 16.3785 15 18V21H3V18ZM9 11.25C8.31104 11.25 7.66548 11.0642 7.11068 10.74C5.9977 10.0896 5.25 8.88211 5.25 7.5C5.25 5.42893 6.92893 3.75 9 3.75C10.2267 3.75 11.3158 4.33901 12 5.24963C12.6842 4.33901 13.7733 3.75 15 3.75C17.0711 3.75 18.75 5.42893 18.75 7.5C18.75 8.88211 18.0023 10.0896 16.8893 10.74C16.3345 11.0642 15.689 11.25 15 11.25C14.311 11.25 13.6655 11.0642 13.1107 10.74C12.6776 10.4869 12.2999 10.1495 12 9.75036C11.7001 10.1496 11.3224 10.4869 10.8893 10.74C10.3345 11.0642 9.68896 11.25 9 11.25ZM13.5 18V19.5H4.5V18C4.5 15.5147 6.51472 13.5 9 13.5C11.4853 13.5 13.5 15.5147 13.5 18ZM11.25 7.5C11.25 8.74264 10.2426 9.75 9 9.75C7.75736 9.75 6.75 8.74264 6.75 7.5C6.75 6.25736 7.75736 5.25 9 5.25C10.2426 5.25 11.25 6.25736 11.25 7.5ZM15 5.25C13.7574 5.25 12.75 6.25736 12.75 7.5C12.75 8.74264 13.7574 9.75 15 9.75C16.2426 9.75 17.25 8.74264 17.25 7.5C17.25 6.25736 16.2426 5.25 15 5.25Z" />
  6508.                                                     </g>
  6509.                                                 </svg>`
  6510.                             }
  6511.                         </button>
  6512.                     </td>
  6513.                     <td class="date-input" value="${duedate}"  style=" justify-items:center; align-items: center;border-left: 1px solid #CED4DA; padding-left: 10px; color: ${color};">
  6514.                         <button title="Change Date" class="assign-btn"
  6515.                         {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  6516.                         onclick="openDueDateDropdown(${taskId},this)"
  6517.                         {% endif %}
  6518.                         style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6519.  
  6520.                         ${label}
  6521.                     </button>
  6522.                     </td>
  6523.                     <td class="priority-input" value="${priorityText}" title="${priorityText}"  style="border-left: 1px solid #CED4DA; padding-left: 10px; text-align: center; vertical-align: middle;justify-content: center; display:flex;">
  6524.                                             <button title="Change Priority" class="assign-btn"
  6525.                                            
  6526.                                             onclick="openPriorityDropdown(${taskId},this)" style="border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6527.  
  6528.                                             ${priorityIcon || '-' }
  6529.                                             </button>
  6530.                                         </td>                  
  6531.                     <td class="bountie-input" style="padding-left: 10px; justify-content: center; justify-items:center;">
  6532.                     <button title="Change Bounties"  id="${taskId}" value="${bountyInput || '1'}" class="assign-btn bounty-btn"
  6533.                     {% if is_user_spm or request.user == project_detail.manager or hat_type == 'projectManager' %}
  6534.                     onclick="openBountyDropdown(${taskId},this)"
  6535.                     {% endif %}style="justify-content: center;width:35px; border: none; background: none; cursor: pointer; display: flex; align-items: center;">
  6536.                     <div>${bountyInput || '-'}</div>
  6537.                     </button>
  6538.                 </td>
  6539.                 `;
  6540.             }
  6541.            
  6542.  
  6543.             // append the new task before the bitton task row
  6544.             const tableBody = milestoneSection.querySelector('tbody');
  6545.             const buttonRow = milestoneSection.querySelector('.add-task-row');
  6546.             tableBody.insertBefore(newTaskRow, buttonRow);
  6547.             buttonRow.remove();
  6548.             rowIsOpen = false;
  6549.             document.removeEventListener('keydown', handleKeydown);
  6550.            
  6551.             updateProgress(newTaskRow);
  6552.             enforceTableCellHeight(35);
  6553.  
  6554.  
  6555.         }
  6556.  
  6557.         function updateTaskStatus(taskId, checkbox) {
  6558.             checkbox.checked = !checkbox.checked; // Revert the automatic change
  6559.             const newStatus = !checkbox.checked ? 'C' : 'I';
  6560.             const taskRow = checkbox.closest('tr');
  6561.            
  6562.             // Store references to related elements
  6563.             const parentTaskId = taskRow.getAttribute('data-task-id');
  6564.             const isSubtask = taskRow.classList.contains('subtask-row');
  6565.             let parentRow = null;
  6566.            
  6567.             if (isSubtask) {
  6568.                 parentRow = document.getElementById(parentTaskId);
  6569.             }
  6570.  
  6571.             fetch(`/project/update-subtask-status/${taskId}/`, {
  6572.                 method: 'POST',
  6573.                 headers: {
  6574.                     'Content-Type': 'application/json',
  6575.                 },
  6576.                 body: JSON.stringify({ status: newStatus })
  6577.             })
  6578.             .then(response => {
  6579.                 if (!response.ok) {
  6580.                     throw new Error('Failed to update task status.');
  6581.                 }
  6582.                 return response.json();
  6583.             })
  6584.             .then(data => {
  6585.                 checkbox.checked = !checkbox.checked;
  6586.                 // Update task's status attributes
  6587.                 taskRow.setAttribute('data-status', newStatus);
  6588.                 taskRow.setAttribute('value', newStatus);
  6589.                
  6590.                 if (filtered === "pending") {
  6591.                     if (checkbox.checked) {
  6592.                         taskRow.setAttribute('hidden', 'true');
  6593.                        
  6594.                         // If it's a subtask, handle parent task visibility
  6595.                         if (isSubtask && parentRow) {
  6596.                             let allSubtasksComplete = true;
  6597.                             const siblingSubtasks = document.querySelectorAll(`.subtask-row[data-task-id="${parentTaskId}"]`);
  6598.                             siblingSubtasks.forEach(subtask => {
  6599.                                 if (subtask.getAttribute('value') !== 'C') {
  6600.                                     allSubtasksComplete = false;
  6601.                                 }
  6602.                             });
  6603.                            
  6604.                             if (allSubtasksComplete) {
  6605.                                 parentRow.setAttribute('hidden', 'true');
  6606.                             }
  6607.                         }
  6608.                     }
  6609.                 } else if (filtered === "all") {
  6610.                     // In "all" view, never hide the task
  6611.                     taskRow.removeAttribute('hidden');
  6612.                    
  6613.                     // If it's a parent task, ensure subtasks visibility is maintained
  6614.                     if (!isSubtask) {
  6615.                         const subtasks = document.querySelectorAll(`.subtask-row[data-task-id="${taskId}"]`);
  6616.                         subtasks.forEach(subtask => {
  6617.                             if (taskRow.dataset.open === "true") {
  6618.                                 subtask.removeAttribute('hidden');
  6619.                             }
  6620.                         });
  6621.                     }
  6622.                 }
  6623.  
  6624.                 // Update progress indicators
  6625.                 const progressBar = taskRow.querySelector('.status-bar-completed');
  6626.                 if (progressBar) {
  6627.                     progressBar.style.width = checkbox.checked ? '100%' : '0%';
  6628.                 }
  6629.  
  6630.                 const tooltip = taskRow.querySelector('.progress-tooltip');
  6631.                 if (tooltip) {
  6632.                     tooltip.textContent = checkbox.checked ? 'Task completed' : 'Task pending';
  6633.                 }
  6634.  
  6635.                 // Update parent task progress if this is a subtask
  6636.                 if (isSubtask && parentRow) {
  6637.                     updateProgress(parentRow);
  6638.                 }
  6639.             })
  6640.             .catch(error => {
  6641.                 console.error('Error updating task status:', error);
  6642.                 alert('Failed to update task status. Please try again.');
  6643.             });
  6644.         }
  6645.  
  6646.  
  6647.         function editTask(subtaskId) {
  6648.             const taskNameSpan = document.querySelector(`#task-name-${subtaskId}`);
  6649.            
  6650.             // Create input field with current task name
  6651.             const inputField = document.createElement('input');
  6652.             inputField.type = 'text';
  6653.             inputField.value = taskNameSpan.textContent;
  6654.            
  6655.             // Replace the span with the input field
  6656.             taskNameSpan.replaceWith(inputField);
  6657.            
  6658.             // Focus on the input field
  6659.             inputField.focus();
  6660.        
  6661.             // Function to save the task name (send API call to backend)
  6662.             function saveTaskName() {
  6663.                 const newTaskName = inputField.value.trim();
  6664.                
  6665.                 if (newTaskName) {
  6666.                     // Prepare data to send to the backend
  6667.                     const data = {
  6668.                         taskId: subtaskId,
  6669.                         name: newTaskName
  6670.                     };
  6671.                    
  6672.                     // Make an API call to the backend to save the new task name
  6673.                     fetch(`/project/rename/${subtaskId}/`, {
  6674.                         method: 'POST', // or 'PUT', depending on your backend API
  6675.                         headers: {
  6676.                             'Content-Type': 'application/json',
  6677.                            
  6678.                         },
  6679.                         body: JSON.stringify(data)
  6680.                     })
  6681.                     .then(response => response.json())
  6682.                     .then(updatedTask => {
  6683.                         // If the request was successful, replace the input with the updated task name
  6684.                         const updatedTaskNameSpan = document.createElement('span');
  6685.                         updatedTaskNameSpan.classList.add('task-name');
  6686.                         updatedTaskNameSpan.id = `task-name-${subtaskId}`;
  6687.                         updatedTaskNameSpan.textContent = updatedTask.name; // Use updated name from backend
  6688.        
  6689.                         inputField.replaceWith(updatedTaskNameSpan);
  6690.                     })
  6691.                     .catch(error => {
  6692.                         console.error('Error renaming task:', error);
  6693.                        
  6694.                         // Optionally, handle errors (e.g., revert the input back to the original task name)
  6695.                         inputField.replaceWith(taskNameSpan);
  6696.                     });
  6697.                 } else {
  6698.                     // If the input field is empty, revert to the old value (optional)
  6699.                     const updatedTaskNameSpan = document.createElement('span');
  6700.                     updatedTaskNameSpan.classList.add('task-name');
  6701.                     updatedTaskNameSpan.id = `task-name-${subtaskId}`;
  6702.                     updatedTaskNameSpan.textContent = taskNameSpan.textContent; // Or previous task name
  6703.                     inputField.replaceWith(updatedTaskNameSpan);
  6704.                 }
  6705.             }
  6706.        
  6707.             // Save the task name on Enter key press
  6708.             inputField.addEventListener('keydown', function(event) {
  6709.                 if (event.key === 'Enter') {
  6710.                     saveTaskName();
  6711.                 }
  6712.             });
  6713.        
  6714.             // Save the task name when the input field loses focus (blur event)
  6715.             inputField.addEventListener('blur', saveTaskName);
  6716.         }
  6717.        
  6718.         // Helper function to get CSRF token (if applicable)
  6719.         function getCSRFToken() {
  6720.             const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
  6721.             return csrfToken;
  6722.         }
  6723.        
  6724.        
  6725.         function updateFlag(svg) {
  6726.             const header = svg.closest('tr');
  6727.             const taskId = header.id;
  6728.             const flagPath = svg.querySelector('path');
  6729.             const currentColor = flagPath.getAttribute('fill');
  6730.             let status = "C";
  6731.            
  6732.             if (currentColor === '#DD1D43'  || currentColor === 'grey') {
  6733.                 flagPath.setAttribute('fill', 'green');
  6734.                 status = "C";
  6735.  
  6736.             } else {
  6737.                 // Currently complete, changing to incomplete
  6738.                 // Check due date to determine color
  6739.                 const dueDateCell = header.querySelector('.date-input');
  6740.                 const dueDateValue = dueDateCell.getAttribute('value');
  6741.                 const today = new Date();
  6742.                 today.setHours(0, 0, 0, 0); // Set to beginning of day for comparison
  6743.                
  6744.                 // More robust date parsing
  6745.                 if (dueDateValue) {
  6746.                     const dueDate = new Date(dueDateValue);
  6747.                     if (!isNaN(dueDate.getTime()) && dueDate > today) {
  6748.                         flagPath.setAttribute('fill', 'grey'); // Future due date
  6749.                     } else {
  6750.                         flagPath.setAttribute('fill', '#DD1D43'); // Past due date
  6751.                     }
  6752.                 } else {
  6753.                     flagPath.setAttribute('fill', '#DD1D43'); // No due date, default to red
  6754.                 }
  6755.                 status = "I";
  6756.             }
  6757.            
  6758.             fetch(`/project/update-subtask-status/${taskId}/`, {
  6759.                 method: 'POST',
  6760.                 headers: {
  6761.                     'Content-Type': 'application/json',
  6762.                 },
  6763.                 body: JSON.stringify({ status: status }) // Send the new status
  6764.             })
  6765.             .then(response => {
  6766.                 if (!response.ok) {
  6767.                     throw new Error('Network response was not ok');
  6768.                 }
  6769.                 return response.json(); // Return the response as JSON
  6770.             })
  6771.             .then(data => {
  6772.                 console.log('Success:', data); // Handle the success response if needed
  6773.             })
  6774.             .catch((error) => {
  6775.                 console.error('Error updating task status:', error);
  6776.             });
  6777.            
  6778.         }
  6779.             /* helper funcs */
  6780.             function openClickUpModal() {
  6781.                 event.preventDefault();
  6782.                 document.getElementById('clickupModal').style.display = 'block';
  6783.             }
  6784.  
  6785.             function closeClickupModal(event) {
  6786.                 event.preventDefault();
  6787.                 const form = document.getElementById('clickupForm')
  6788.                 form.reset();
  6789.                 document.getElementById('clickupModal').style.display = 'none';
  6790.             }
  6791.             function selectPMFolder(event) {
  6792.                 event.preventDefault(); // Prevent form submission
  6793.        
  6794.                 // Retrieve the selected project ID
  6795.                 const selectedProjectInput = document.querySelector('input[name="existing-project"]:checked');
  6796.        
  6797.                 if (!selectedProjectInput) {
  6798.                     alert("Please select a project to sync.");
  6799.                     return; // Exit the function if no project is selected
  6800.                 }
  6801.        
  6802.                 const selectedProjectName = selectedProjectInput.nextSibling.nodeValue.trim(); // This retrieves the project name
  6803.                
  6804.                 // Create the ClickUp mapping object
  6805.                 const clickupMapping = {
  6806.                     project_id: projectId,
  6807.                     project_name: selectedProjectName
  6808.                 };
  6809.        
  6810.                 // Call your function to create the mapping (replace with actual implementation)
  6811.                 createClickUpMapping(clickupMapping);
  6812.                
  6813.                 // Optionally, close the modal after selection
  6814.                 closeClickupModal(event);
  6815.             }
  6816.  
  6817.             function createClickUpMapping(mapping) {
  6818.                 fetch('/project/create_clickup_mapping/', {
  6819.                     method: 'POST',
  6820.                     headers: {
  6821.                         'Content-Type': 'application/json',
  6822.                     },
  6823.                     body: JSON.stringify(mapping),
  6824.                 })
  6825.                 .then(response => response.json())
  6826.                 .then(data => {
  6827.                     console.log('Success:', data);
  6828.                    
  6829.                 })
  6830.                 .catch((error) => {
  6831.                     console.error('Error:', error);
  6832.                    
  6833.                 });
  6834.             }
  6835.            
  6836.  
  6837.             //function for dd/mm/yyyy date format
  6838.             function formatDateToDDMMYYYY(dateString) {
  6839.                 const [year, month, day] = dateString.split('-');
  6840.                 return `${day}/${month}/${year}`;
  6841.             }
  6842.  
  6843.             function formatDateToDDMMYYYY_day(dateString) {
  6844.                 if (dateString != ''){
  6845.                     const [month, day,year] = dateString.split('/');
  6846.                 return `${day}/${month}/${year}`;
  6847.                 }
  6848.                 return "Not Set"
  6849.             }
  6850.  
  6851.             function formatDateToYYYYMMDD(dateString) {
  6852.                 const [day, month, year] = dateString.split('/');
  6853.                 return `${year}-${month}-${day}`;
  6854.             }
  6855.  
  6856.             //function for edit project key detials
  6857.             function editMode() {
  6858.                 document.getElementById('view-mode').style.display = 'none';
  6859.                 document.getElementById('edit-mode').style.display = 'flex';
  6860.             }
  6861.             //function for cancel edit project key detials
  6862.             function cancelEdit() {
  6863.          
  6864.                 document.getElementById('edit-mode').style.display = 'none';
  6865.                 document.getElementById('view-mode').style.display = 'flex';
  6866.             }
  6867.  
  6868.             ////function for save project key detials
  6869.  
  6870.             function saveChanges() {
  6871.                 const clientNames = Array.from(document.querySelectorAll('input[name="client-name"]'))
  6872.                     .map(input => input.value.trim())
  6873.                     .filter(value => value);
  6874.  
  6875.                 const clientEmails = Array.from(document.querySelectorAll('input[name="client-email"]'))
  6876.                     .map(input => input.value.trim())
  6877.                     .filter(value => value);
  6878.  
  6879.                 const clientContact = Array.from(document.querySelectorAll('input[name="client-mobile"]'))
  6880.                     .map(input => input.value.trim())
  6881.                     .filter(value => value);
  6882.  
  6883.  
  6884.                 const projectName = document.getElementById('project-name').value;
  6885.                 const startDate = document.getElementById('start-date').value;
  6886.                 const endDate = document.getElementById('tentative-end-date').value;
  6887.                 const companyName = document.getElementById('company-name').value;
  6888.                 //const clientName = document.getElementById('client-name').value;
  6889.                 //const email = document.getElementById('email').value;
  6890.                 // const mobile = document.getElementById('mobile').value;
  6891.                 const address = document.getElementById('address').value;
  6892.                 const gstin = document.getElementById('gstin').value;
  6893.                 const pan = document.getElementById('pan').value;
  6894.                 const proposal_doc = document.getElementById('proposal_doc').value;
  6895.                 // const milestone = document.getElementById('milestone-container').value;
  6896.                 let data = {
  6897.                         project_id: projectId,
  6898.                         project_name: projectName,
  6899.                         start_date: startDate,
  6900.                         end_date: endDate,
  6901.                         company_name: companyName,
  6902.                         client_name: clientNames,
  6903.                         email: clientEmails,
  6904.                         mobile: clientContact,
  6905.                         address: address,
  6906.                         gstin: gstin,
  6907.                         pan: pan,
  6908.                         proposal_doc: proposal_doc,
  6909.                         milestone: milestoneStatuses
  6910.                     }
  6911.  
  6912.                 // Send data to backend
  6913.                 fetch('/project/update_details/', {
  6914.                     method: 'POST',
  6915.                     headers: {
  6916.                         'Content-Type': 'application/json',
  6917.  
  6918.                     },
  6919.                     body: JSON.stringify(data)
  6920.                 })
  6921.                     // .then(console.log(milestoneStatuses))
  6922.                     .then(response => response.json())
  6923.                     .then(data => {
  6924.                         if (data.success) {
  6925.                             cancelEdit();
  6926.                             window.location.reload();
  6927.                             alert('Project details updated successfully!');
  6928.                            
  6929.                         // Call to tasks/update/ after successful update
  6930.                    
  6931.                     } else {
  6932.                         alert('Failed to update project details. ' + data.message);
  6933.                     }
  6934.                 });
  6935.             }
  6936.  
  6937.             //function for apllying color dynamically for due date
  6938.             function applyDueDateColors() {
  6939.                 // select all cells with the class due-date-cell
  6940.                 const dueDateCells = document.querySelectorAll('.due-date-cell');
  6941.  
  6942.                 // iterate over each cell and apply the apropriate class based on the text content
  6943.                 dueDateCells.forEach(cell => {
  6944.                     const text = cell.textContent.trim();
  6945.  
  6946.                     if (text === 'Tomorrow') {
  6947.                         cell.classList.add('due-date-tomorrow');
  6948.                     } else if (text.includes('days ago')) {
  6949.                         cell.classList.add('due-date-days-ago');
  6950.                     } else if (text === 'No due date') {
  6951.                         cell.classList.add('due-date-no-date');
  6952.                     }
  6953.                 });
  6954.             }
  6955.  
  6956.  
  6957.  
  6958.             // function to apply style internship days left and dynamically add popup
  6959.             function applyInternshipEndStyles(daysLeftData) {
  6960.                 daysLeftData.forEach(({ rowId, daysLeft }) => {
  6961.                     const row = document.getElementById(rowId);
  6962.                     if (row) {
  6963.                         const teamMemberNameElement = row.querySelector('.team-member-name');
  6964.  
  6965.                         if (daysLeft <= 30) {
  6966.  
  6967.                             teamMemberNameElement.style.backgroundColor = '#FFBEC0';
  6968.                             teamMemberNameElement.style.color = '#A90420';
  6969.                             teamMemberNameElement.style.cursor = 'pointer';
  6970.  
  6971.                             let popupElement = teamMemberNameElement.querySelector('.team-member-alert-internship-end-popup');
  6972.  
  6973.                             if (!popupElement) {
  6974.                                 popupElement = document.createElement('div');
  6975.                                 popupElement.className = 'team-member-alert-internship-end-popup';
  6976.                                 teamMemberNameElement.appendChild(popupElement);
  6977.                             }
  6978.                             popupElement.textContent = `${daysLeft} days remaining`;
  6979.                         }
  6980.                     }
  6981.                 });
  6982.             }
  6983.  
  6984.             function populateSelectOptions() {
  6985.                 const selectElements = document.querySelectorAll('.searchable-select');
  6986.                 selectElements.forEach(select => {
  6987.                     select.innerHTML = '<option value="">Select Name</option>';
  6988.                     teamMembers.forEach(member => {
  6989.                         const option = document.createElement('option');
  6990.                         option.value = member.id;
  6991.                         option.textContent = member.username;
  6992.                         select.appendChild(option);
  6993.                     });
  6994.                     $(select).select2();
  6995.                 });
  6996.             }
  6997.             function updateMemberDetails(selectElement) {
  6998.                 const selectedId = parseInt(selectElement.value, 10);
  6999.                 const row = selectElement.closest('tr');
  7000.                 const roleColumn = row.querySelector('#role-column');
  7001.                 const availabilityColumn = row.querySelector('#availability-column');
  7002.                 const contactColumn = row.querySelector('#contact-column');
  7003.  
  7004.                 const member = replacementMembers.find(member => member.id === selectedId);
  7005.  
  7006.                 if (member) {
  7007.                
  7008.                     availabilityColumn.textContent = member.availability;
  7009.                     contactColumn.innerHTML = `
  7010.                 <div>Email: ${member.email_address}</div>
  7011.                 <div>Mob: ${member.phone_number}</div>
  7012.                 `;
  7013.                     } else {
  7014.                         roleColumn.textContent = 'Role';
  7015.                         availabilityColumn.textContent = 'Availability';
  7016.                         contactColumn.innerHTML = `
  7017.                     <div>Email: </div>
  7018.                     <div>Mob: </div>
  7019.                 `;
  7020.                     }
  7021.                 }
  7022.                 document.querySelectorAll('.display-milestone').forEach(milestoneElement => {
  7023.                
  7024.                     const milestoneId = milestoneElement.id;
  7025.                     const status = milestoneStatuses[milestoneId].status || 'none';
  7026.                     updateMilestoneColor(milestoneElement, status);
  7027.             });
  7028.  
  7029.             async function fetchDaysLeftData(projectId) {
  7030.                 try {
  7031.                     const response = await fetch(`/project/days_left_data/${projectId}/`);
  7032.                     const data = await response.json();
  7033.                     if (data.errors && data.errors.length > 0) {
  7034.                         console.log('Errors occurred while fetching days left:', data.errors);
  7035.                     }
  7036.                     daysLeftData = data.days_left_data;
  7037.                     applyInternshipEndStyles(daysLeftData);
  7038.                 } catch (error) {
  7039.                     console.error('Error fetching days left data:', error);
  7040.                 }
  7041.             }
  7042.  
  7043.            
  7044.             async function updateAlertData(projectId) {
  7045.                 try {
  7046.                     // Fetch the alert data from the backend
  7047.                     const response = await fetch(`/project/alert_data/${projectId}/`);
  7048.                    
  7049.                     const data = await response.json();
  7050.                     if (data.errors && data.errors.length > 0) {
  7051.                         console.log('Errors occurred while fetching alerts:', data.errors);
  7052.                     }
  7053.                     alert_data = data.alerts;
  7054.  
  7055.                     alert_data.forEach(alert => {
  7056.                         const memberRow = document.getElementById(`${alert.rowId}`);
  7057.                         const alertCell = memberRow.querySelector(".team-member-alert");
  7058.                         // Build the alert message based on the alert data
  7059.                         let alertMessage = '';
  7060.                         if (alert.githubPushed.length > 0) {
  7061.                             alertMessage +=
  7062.                            ` <span class="team-member-alert-no-github-push" id="git_person">
  7063.                                 <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  7064.                                     <path d="M16 3.66667V7.66667C16 8.21933 15.552 8.66667 15 8.66667C14.448 8.66667 14 8.21933 14 7.66667V3.66667C14 2.748 13.2527 2 12.3333 2H3.66667C2.748 2 2 2.748 2 3.66667V12.3333C2 13.252 2.748 14 3.66667 14C4.21933 14 4.66667 14.4473 4.66667 15C4.66667 15.5527 4.21933 16 3.66667 16C1.64467 16 0 14.3553 0 12.3333V3.66667C0 1.64467 1.64467 0 3.66667 0H12.3333C14.3547 0 16 1.64467 16 3.66667ZM15.824 13.9907C16.0567 14.4147 16.058 14.9133 15.832 15.3313C15.606 15.7493 15.2013 16 14.748 16H7.252C6.79933 16 6.394 15.75 6.16867 15.3313C5.94267 14.9127 5.94467 14.414 6.17267 13.9967L9.924 7.32067C10.148 6.91333 10.5513 6.66667 11.0007 6.66667C11.45 6.66667 11.8533 6.91333 12.08 7.32733L15.824 13.9907ZM11.9993 13.6667C11.9993 13.1147 11.5513 12.6667 10.9993 12.6667C10.4473 12.6667 9.99933 13.1147 9.99933 13.6667C9.99933 14.2187 10.4473 14.6667 10.9993 14.6667C11.5513 14.6667 11.9993 14.2187 11.9993 13.6667ZM11.9993 9.66667C11.9993 9.114 11.5513 8.66667 10.9993 8.66667C10.4473 8.66667 9.99933 9.114 9.99933 9.66667C9.99933 10.2193 10.4473 10.6667 10.9993 10.6667C11.5513 10.6667 11.9993 10.2193 11.9993 9.66667Z" fill="#DD1D43"/>
  7065.                                 </svg>
  7066.                                 <div class="team-member-alert-no-github-push-popup">No GitHub pushes: </br> ${alert.githubPushed.join(', ')}</div>
  7067.                             </span>`;
  7068.                         }
  7069.                        
  7070.                         if (alert.isAbsentToday) {
  7071.                             alertMessage +=  
  7072.                             `<span class="team-member-alert-absent">
  7073.                             <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="15" viewBox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
  7074.                                 <g>
  7075.                                     <circle style="fill:#CC3333;" cx="63.93" cy="64" r="60"/>
  7076.                                     <circle style="fill:#F44336;" cx="60.03" cy="63.1" r="56.1"/>
  7077.                                     <path style="fill:#FF8A80;" d="M23.93,29.7c4.5-7.1,14.1-13,24.1-14.8c2.5-0.4,5-0.6,7.1,0.2c1.6,0.6,2.9,2.1,2,3.8
  7078.                                        c-0.7,1.4-2.6,2-4.1,2.5c-9.38,3.1-17.47,9.21-23,17.4c-2,3-5,11.3-8.7,9.2C17.43,45.7,18.23,38.5,23.93,29.7z"/>
  7079.                                 </g>
  7080.                             </svg>
  7081.                             <div class="team-member-alert-absent-popup">Absent</div>
  7082.                         </span>
  7083.                         `;
  7084.                         }
  7085.  
  7086.                         if (alert.upcomingLeaves) {
  7087.                             alertMessage +=
  7088.                             `<span class="team-member-alert-leave">
  7089.                                 <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="15" viewBox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
  7090.                                     <g>
  7091.                                         <circle style="fill:#F2A600;" cx="63.93" cy="64" r="60"/>
  7092.                                         <circle style="fill:#FFCC32;" cx="60.03" cy="63.1" r="56.1"/>
  7093.                                         <path style="fill:#FFF170;" d="M23.93,29.7c4.5-7.1,14.1-13,24.1-14.8c2.5-0.4,5-0.6,7.1,0.2c1.6,0.6,2.9,2.1,2,3.8
  7094.                                            c-0.7,1.4-2.6,2-4.1,2.5c-9.38,3.1-17.47,9.21-23,17.4c-2,3-5,11.3-8.7,9.2C17.43,45.7,18.23,38.5,23.93,29.7z"/>
  7095.                                     </g>
  7096.                                 </svg>
  7097.                                 <div class="team-member-alert-leave-popup">${ alert.totalDays } upcoming leaves <br> ${ alert.leaveDates }</div>
  7098.                             </span>`
  7099.                            
  7100.                         }
  7101.                        
  7102.  
  7103.                         // Update the alert cell with the constructed message
  7104.                         alertCell.innerHTML = alertMessage;
  7105.                     });
  7106.                 } catch (error) {
  7107.                     console.error('Failed to fetch alert data:', error);
  7108.                 }
  7109.             }
  7110.  
  7111.             applyDueDateColors();
  7112.             function enforceTableCellHeight(height) {
  7113.                
  7114.                 const rows = document.querySelectorAll(".task-table tr");
  7115.                 const cells = document.querySelectorAll(".task-table th, .task-table td");
  7116.                 const rowAdd = document.querySelectorAll('.add-task-rows');
  7117.                 const AddCell = document.querySelectorAll('.add-task-rows td');
  7118.                
  7119.                 // Apply height to all rows
  7120.                 rows.forEach(row => {
  7121.                     row.style.height = `${height}px`;
  7122.                     row.style.paddingTop = "0px";
  7123.                     row.style.paddingBottom = "0px";
  7124.                     row.style.justifyItems = "center";
  7125.                     row.style.justifyContent= "center";
  7126.                 });
  7127.                 rowAdd.forEach(row => {
  7128.                     row.style.height = `35px`;
  7129.                     row.style.paddingTop = "2px";
  7130.                     row.style.paddingBottom = "2px";
  7131.                 });
  7132.                
  7133.                 cells.forEach(cell => {
  7134.                     cell.style.height = `${height}px`;
  7135.                     cell.style.lineHeight = `${height}px`; // Centers text vertically
  7136.                     cell.style.verticalAlign = "middle";   // Ensures vertical alignment
  7137.                     cell.style.margin = "0px";
  7138.                     cell.style.paddingTop = "0px";
  7139.                     cell.style.paddingBottom = "0px";
  7140.                 });
  7141.  
  7142.                 AddCell.forEach(cell => {
  7143.                     cell.style.height = `35px`;
  7144.                     cell.style.lineHeight = `35px`;
  7145.                     cell.style.verticalAlign = "middle";  
  7146.                     cell.style.justifyContent = "center";
  7147.                     cell.style.paddingTop = "8px";
  7148.                     cell.style.paddingBottom = "8px";
  7149.                 });
  7150.             }
  7151.            
  7152.  
  7153.             function openCreateDocumentForm() {
  7154.                 document.getElementById("create-document-modal").style.display = "flex";
  7155.             }
  7156.            
  7157.             function closeCreateDocumentForm() {
  7158.                 document.getElementById("create-document-modal").style.display = "none";
  7159.             }
  7160.            
  7161.             //submit created documnet
  7162.             async function submitCreateDocumentForm() {
  7163.                 const title = document.getElementById('createDocumentName').value;
  7164.                 const link = document.getElementById('createDocumentLink').value;
  7165.                 const type = document.getElementById('documentType').value;
  7166.                 const permissions = document.getElementById('documentPermissions').value;
  7167.  
  7168.                 if (!title || !link || !type || !permissions) {
  7169.                     alert('Please fill in all fields.');
  7170.                     return;
  7171.                 }
  7172.  
  7173.                 const data = {
  7174.                     title,
  7175.                     link,
  7176.                     type,
  7177.                     permissions,
  7178.                     project_id: projectId
  7179.                 };
  7180.                 alert('Document created successfully');
  7181.                 try {
  7182.                     const response = await fetch('/project/create-document/', {
  7183.                         method: 'POST',
  7184.                         headers: {
  7185.                             'Content-Type': 'application/json',
  7186.                             'X-CSRFToken': '{{ csrf_token }}',
  7187.                         },
  7188.                         body: JSON.stringify(data)
  7189.                     });
  7190.                     const result = await response.json();
  7191.                     alert('Document created successfully again');
  7192.                     if (result.status === 'success') {
  7193.                         closeCreateDocumentForm();
  7194.                         saveNewLinks_2_with_parameter(title, link);
  7195.                         alert("Document created successfully");
  7196.                     } else {
  7197.                         alert('Error: ' + (result.message || 'Unknown error'));
  7198.                     }
  7199.                 } catch (error) {
  7200.                     console.error('Error:', error);
  7201.                     alert('Error creating document: ' + error.message);
  7202.                 }
  7203.             }
  7204.            
  7205.             // Close modal when clicking outside of it
  7206.             window.onclick = function(event) {
  7207.                 const modal = document.getElementById("create-document-modal");
  7208.                 if (event.target === modal) {
  7209.                     modal.style.display = "none";
  7210.                 }
  7211.             }
  7212.  
  7213.             // Function to trigger the file input click
  7214.             function triggerFileUpload() {
  7215.                 print('inside trigger');
  7216.                 document.getElementById('fileInput').click();
  7217.             }
  7218.        
  7219.             // Function to handle the file upload process
  7220.             async function handleFileUpload(event) {
  7221.                 const fileInput = event.target;
  7222.                 const file = fileInput.files[0];  // Get the first file selected
  7223.            
  7224.            
  7225.                 if (!file) {
  7226.                     console.log('No file selected.');
  7227.                     return;
  7228.                 }
  7229.            
  7230.                 // Log the uploading status
  7231.                 console.log('Uploading file...');
  7232.            
  7233.                 // Create a FormData object to send the file data
  7234.                 const formData = new FormData();
  7235.                 formData.append('file', file);  // Append the file to FormData
  7236.                 formData.append('projectId', projectId);  // Add project_document_id if needed
  7237.            
  7238.                 // Use Fetch API to send the file to the server
  7239.                 await fetch('/project/upload-project-docs/', {
  7240.                     method: 'POST',
  7241.                     body: formData,
  7242.                     headers: {
  7243.                     'X-CSRFToken': '{{ csrf_token }}', // CSRF token for security
  7244.                 }
  7245.                 })
  7246.                 .then(response => response.json())
  7247.                 .then(data => {
  7248.                     if (data.success) {
  7249.                         console.log('message',data.message,'file_url',data.file_url);
  7250.                         alert('file upload successful');
  7251.  
  7252.                         saveNewLinks_2_with_parameter(data.file_name,data.file_url);
  7253.  
  7254.  
  7255.                     } else {
  7256.                         console.log('message',data.message,'error',data.error);
  7257.                     }
  7258.                 })
  7259.                 .catch(error => {
  7260.                     console.error('Fetch Error:', error);
  7261.                 });
  7262.             }
  7263.        
  7264.         async function get_title() {
  7265.             const url = document.getElementById('md-url').value;
  7266.             if (!url) {
  7267.                 alert('No URL provided. Please insert a valid URL.');
  7268.                 return;
  7269.             }
  7270.        
  7271.             const formData = {
  7272.                 url: url,
  7273.                 projectId: projectId,  // Make sure `projectId` is defined somewhere in your code
  7274.             };
  7275.        
  7276.             await fetch('/project/get-file-name/', {
  7277.                 method: 'POST',
  7278.                 headers: {
  7279.                     'Content-Type': 'application/json',
  7280.                     'X-CSRFToken': '{{ csrf_token }}',  // Ensure CSRF token is correctly passed
  7281.                 },
  7282.                 body: JSON.stringify(formData)  
  7283.             })
  7284.             .then(response => response.json())
  7285.             .then(data => {
  7286.                 console.log("Data received from server:", data);
  7287.                 if (data.status === 'success') {
  7288.                     console.log('Success!');
  7289.                     alert("FIle Name Found");
  7290.                     if(!data.title){
  7291.                         console.error("File name error");
  7292.                     }
  7293.                     saveNewLinks_2_with_parameter(data.title,url);
  7294.                 } else {
  7295.                     console.log('Error response:', data);
  7296.                     alert('Error: ' + (data.message || 'Unknown error'));
  7297.                 }
  7298.             })
  7299.             .catch(error => {
  7300.                 console.log(error);
  7301.                 console.error('Error:', error);
  7302.                 alert('An error occurred while Getting the name of the document: ' + error.message);
  7303.             });
  7304.         }
  7305.  
  7306.         function saveNewLinks_2_with_parameter(linkName,linkUrl) {
  7307.             console.log("saveNewLinks_2_with_parameter called");
  7308.             const documentList = document.getElementById('document-list');
  7309.        
  7310.        
  7311.                 if (linkName && linkUrl) {
  7312.                     // Create a new link element
  7313.                     console.log("valid linkname and linkurl");
  7314.                     const newLinkDiv = document.createElement('div');
  7315.                     newLinkDiv.style.display = 'flex';
  7316.                     newLinkDiv.style.justifyContent = 'space-between';
  7317.        
  7318.                     const newLink = document.createElement('a');
  7319.                     newLink.href = linkUrl;
  7320.                     newLink.style.textDecoration = 'underline';
  7321.                     newLink.style.color = '#2F6CE5';
  7322.                     newLink.target = '_blank';
  7323.                     newLink.textContent = linkName;
  7324.        
  7325.                     const timeAgo = document.createElement('div');
  7326.                     timeAgo.style.color = '#939CA3';
  7327.                     timeAgo.textContent = 'Just now';
  7328.        
  7329.                     // Append new elements to the parent div
  7330.                     newLinkDiv.appendChild(newLink);
  7331.                     newLinkDiv.appendChild(timeAgo);
  7332.        
  7333.                     // Append the new link div to the document list
  7334.                     documentList.appendChild(newLinkDiv);
  7335.                 }
  7336.                 document.getElementById('md-url').value="";
  7337.                 window.location.reload();
  7338.             };
  7339.                                                
  7340.             document.addEventListener('DOMContentLoaded', () => {
  7341.                 sortNotifications('github-miss','repo');
  7342.                 try {
  7343.                     enforceTableCellHeight(35);
  7344.                     fetchDaysLeftData(projectId);
  7345.                     updateAlertData(projectId);
  7346.                     const emailIcons = document.querySelectorAll('.email-icon');
  7347.                     emailIcons.forEach(icon => {
  7348.                         icon.addEventListener('click', function () {
  7349.                             const templateId = this.getAttribute('data-template');
  7350.                             const modal = document.getElementById(templateId);
  7351.                             if (modal) {
  7352.                                 modal.style.display = 'block';
  7353.                                
  7354.                             }
  7355.                         });
  7356.                     });
  7357.  
  7358.                     populateSelectOptions();  
  7359.                     const milestoneNames = document.querySelectorAll('.milestone-name');
  7360.                     milestoneNames.forEach(name => {
  7361.  
  7362.                         const start = name.getAttribute('data-start');
  7363.                         const end = name.getAttribute('data-end');
  7364.            
  7365.                         // Format the dates
  7366.                         const formattedStart = formatDateToDDMMYYYY_day(start);
  7367.                         const formattedEnd = formatDateToDDMMYYYY_day(end);
  7368.            
  7369.                         // Update the title attribute for hover display
  7370.                         name.setAttribute('title', `Start Date: ${formattedStart}\nEnd Date: ${formattedEnd}`);
  7371.                        
  7372.                     });
  7373.                     const taskRows = document.querySelectorAll('.task-row');
  7374.                     taskRows.forEach(row => {
  7375.                         updateProgress(row);
  7376.                     });
  7377.  
  7378.                    
  7379.                    
  7380.                
  7381.                     const ownerSelect = document.getElementById('owner');
  7382.                     const orgSelect = document.getElementById('organization');
  7383.            
  7384.                     // Event listener for the owner dropdown
  7385.                     ownerSelect.addEventListener('change', function () {
  7386.                         const selectedOwner = ownerSelect.value;
  7387.            
  7388.                         // Clear the organization dropdown
  7389.                         orgSelect.innerHTML = '<option value="">Select Organization (if applicable)</option>';
  7390.            
  7391.                         if (selectedOwner) {
  7392.                             fetch(`/project/get_user_organizations/?owner=${selectedOwner}`)  // Adjust the URL as needed
  7393.                                 .then(response => response.json())
  7394.                                 .then(data => {
  7395.                                     if (data.organizations) {
  7396.                                         data.organizations.forEach(org => {
  7397.                                             orgSelect.innerHTML += `<option value="${org.login}">${org.login}</option>`;
  7398.                                         });
  7399.                                     }
  7400.                                 })
  7401.                                 .catch(error => console.error('Error fetching organizations:', error));
  7402.                         }
  7403.                     });
  7404.            
  7405.                 } catch (error) {
  7406.                     console.error('Error:', error);
  7407.                 }
  7408.                 (function () {
  7409.                     // toggle task Element
  7410.                     function toggleTaskElement() {
  7411.                         const taskElement = document.querySelectorAll('.task-dashboard-content');
  7412.                         const icons = document.querySelectorAll('.up-icon');
  7413.    
  7414.                         icons.forEach((icon, index) => {
  7415.                             icon.addEventListener('click', function () {
  7416.                                 const taskEle = taskElement[index];
  7417.                                 if (taskEle.style.display === 'flex' || taskEle.style.display === '') {
  7418.                                     taskEle.style.display = 'none';
  7419.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7420.                             <path d="M1 1L7 7L13 1" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7421.                         </svg>`;
  7422.                                 } else {
  7423.                                     taskEle.style.display = 'flex';
  7424.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7425.                             <path d="M13 7L7 1L1 7" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7426.                         </svg>`;
  7427.                                 }
  7428.                             });
  7429.                         });
  7430.                     }
  7431.    
  7432.                     //toggle team element
  7433.                     function toggleTeamElement() {
  7434.                         const teamElement = document.querySelectorAll('.team-member-content');
  7435.                         const icons = document.querySelectorAll('.up-team-member-icon');
  7436.    
  7437.                         icons.forEach((icon, index) => {
  7438.                             icon.addEventListener('click', function () {
  7439.                                 const teamEle = teamElement[index];
  7440.                                 if (teamEle.style.display === 'block') {
  7441.                                     teamEle.style.display = 'none';
  7442.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7443.                             <path d="M1 1L7 7L13 1" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7444.                         </svg>`;
  7445.                                 } else {
  7446.                                     teamEle.style.display = 'block';
  7447.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7448.                             <path d="M13 7L7 1L1 7" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7449.                         </svg>`;
  7450.                                 }
  7451.                             });
  7452.                         });
  7453.                     }
  7454.    
  7455.    
  7456.                     // toggle budget elment
  7457.                     function toggleBudgetElement() {
  7458.                         const budgetElement = document.querySelectorAll('.dashboard-budget-group');
  7459.                         const icons = document.querySelectorAll('.up-budget-icon');
  7460.    
  7461.                         icons.forEach((icon, index) => {
  7462.                             icon.addEventListener('click', function () {
  7463.                                 const budgetEle = budgetElement[index];
  7464.                                 if (budgetEle.style.display === 'block') {
  7465.                                     budgetEle.style.display = 'none';
  7466.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7467.                             <path d="M1 1L7 7L13 1" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7468.                         </svg>`;
  7469.                                 } else {
  7470.                                     budgetEle.style.display = 'block';
  7471.                                     icon.innerHTML = `<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  7472.                             <path d="M13 7L7 1L1 7" stroke="#6D747A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  7473.                         </svg>`;
  7474.                                 }
  7475.                             });
  7476.                         });
  7477.                     }
  7478.    
  7479.    
  7480.                     //
  7481.                     toggleTaskElement();
  7482.                     toggleTeamElement();
  7483.                     toggleBudgetElement();
  7484.  
  7485.  
  7486.                 })();
  7487.                
  7488.                 // Function to fetch repositories for each member
  7489.                 members.forEach(member => {
  7490.                     fetch(`/project/get_user_repo/${member.id}/${projectId}/`) // Adjust the API endpoint as needed
  7491.                         .then(response => response.json())
  7492.                         .then(data => {
  7493.                             const tooltip = document.getElementById(`tooltip-${member.id}`);
  7494.                             const repoIcon = document.getElementById(`repo-icon-${member.id}`);
  7495.        
  7496.                             if (data.length > 0) {
  7497.                                 // Show the icon and populate the tooltip with repository names
  7498.                                 repoIcon.style.display = 'inline-block';
  7499.                                 const repoNames = data.map(repo => repo.name).join(', ');
  7500.                                 tooltip.innerHTML = repoNames;
  7501.                                
  7502.                             } else {
  7503.                                 repoIcon.style.display = 'none'; // Hide the icon if no repos
  7504.                             }
  7505.                         })
  7506.                         .catch(error => console.error('Error fetching repositories:', error));
  7507.                 });
  7508.            
  7509.                 const categories = [
  7510.                     { id: 'tasks-category', triggers: ['task_overdue', 'task_due_today'] },
  7511.                    
  7512.                     { id: 'github-miss-category', triggers: ['git_person'] },
  7513.                     { id: 'notice-period-category', triggers: ['person_notice'] },
  7514.                     { id: 'informational-category', triggers: [] }
  7515.                 ];
  7516.            
  7517.                 // Loop through each category and check if it has relevant notifications
  7518.                 categories.forEach(category => {
  7519.                     const categoryElement = document.getElementById(category.id);
  7520.                     if (categoryElement) {
  7521.                         const notifContainers = categoryElement.querySelectorAll('.notif-container');
  7522.                         let shouldExpand = false;
  7523.            
  7524.                         notifContainers.forEach(container => {
  7525.                             const trigger = container.dataset.trigger;  
  7526.                             if (category.triggers.length === 0 || category.triggers.includes(trigger)) {
  7527.                                 shouldExpand = true;
  7528.                             }
  7529.                         });
  7530.            
  7531.                         if (shouldExpand) {
  7532.                             categoryElement.classList.add('expanded');  // Add 'expanded' class to the category
  7533.                         }
  7534.                     }
  7535.                 });
  7536.  
  7537.                 const tasks = {{ tasks_json |safe }};
  7538.                 const milestone_statuses = {{ milestone_statuses|safe }};
  7539.                
  7540.                 const noMilestonesMessage = document.getElementById("noMilestonesMessage");
  7541.                 const noTasksMessage = document.getElementById("noTasksMessage");
  7542.                 const taskFilterContainer = document.getElementById("taskFilterContainer");
  7543.                
  7544.                 let milestonesInProgress = false;
  7545.                 let tasksExist = false;
  7546.  
  7547.                 // Loop through milestones to check for "on-progress" status
  7548.                 for (const [key, value] of Object.entries(milestone_statuses)) {
  7549.                     if (value.status === "on-progress") {
  7550.                         milestonesInProgress = true;
  7551.  
  7552.                        
  7553.                         const milestoneDiv = document.createElement("div");
  7554.                         milestoneDiv.innerHTML = `<h4>Milestone: ${key}</h4>`;
  7555.  
  7556.                        
  7557.                         const milestoneTasks = tasks.filter(task => task.milestone == key);
  7558.                        
  7559.                         if (milestoneTasks.length > 0) {
  7560.                             tasksExist = true;
  7561.                             milestoneTasks.forEach(task => {
  7562.                                 const taskDiv = document.createElement("div");
  7563.                                 taskDiv.textContent = `Task: ${task.name}`;
  7564.                                 milestoneDiv.appendChild(taskDiv);
  7565.                             });
  7566.                         }
  7567.  
  7568.                        
  7569.                     }
  7570.                 }
  7571.                
  7572.                 // Show messages based on conditions
  7573.                 if (!milestonesInProgress) {
  7574.                     taskFilterContainer.style.display = "none";
  7575.                     noMilestonesMessage.style.display = "block";
  7576.                 } else if (!tasksExist) {
  7577.                     taskFilterContainer.style.display = "none";
  7578.                     noTasksMessage.style.display = "block";
  7579.                 }
  7580.             });
  7581.  
  7582.     function openDelayModal() {
  7583.         document.getElementById("delayModal").style.display = "flex";
  7584.         updateSecondDropdown();
  7585.         updateDelayText();
  7586.     }
  7587.  
  7588.     document.getElementById("delayModal").addEventListener("click", function(e) {
  7589.         if (e.target === this) {
  7590.             this.style.display = "none";
  7591.         }
  7592.     });
  7593.  
  7594.     document.getElementById("daysInput").addEventListener("input", updateDelayText);
  7595.     document.getElementById("typeSelect").addEventListener("change", updateDelayText);
  7596.  
  7597.     function updateDelayText() {
  7598.         const type = document.getElementById("typeSelect").value;
  7599.         const days = document.getElementById("daysInput").value;
  7600.         let label = type.charAt(0).toUpperCase() + type.slice(1);
  7601.         document.getElementById("delayText").innerText = `The ${label} is delayed by ${days} days.`;
  7602.     }
  7603.  
  7604.     async function updateSecondDropdown() {
  7605.         const typeSelect = document.getElementById("typeSelect").value;
  7606.         const secondSelect = document.getElementById("secondSelect");
  7607.  
  7608.         secondSelect.innerHTML = "";
  7609.  
  7610.         if (typeSelect === "project") {
  7611.             secondSelect.disabled = true;
  7612.             secondSelect.innerHTML = `<option value="${projectId}">β€”</option>`;
  7613.             return;
  7614.         }
  7615.  
  7616.         secondSelect.disabled = false;
  7617.         secondSelect.innerHTML = `<option>Loading...</option>`;
  7618.  
  7619.         try {
  7620.             const res = await fetch(`/project/api/get-items/?type=${typeSelect}&project_id=${projectId}`);
  7621.             if (!res.ok) throw new Error("API request failed");
  7622.  
  7623.             const items = await res.json();
  7624.             secondSelect.innerHTML = "";
  7625.  
  7626.             if (!Array.isArray(items) || items.length === 0) {
  7627.                 secondSelect.innerHTML = `<option>No items found</option>`;
  7628.                 return;
  7629.             }
  7630.  
  7631.             items.forEach(item => {
  7632.                 const opt = document.createElement("option");
  7633.                 opt.value = item.id;
  7634.                 opt.text = item.name;
  7635.                 secondSelect.add(opt);
  7636.             });
  7637.  
  7638.         } catch (err) {
  7639.             console.error(err);
  7640.             secondSelect.innerHTML = `<option>Error loading data</option>`;
  7641.         }
  7642.     }
  7643.  
  7644.    async function submitDelay() {
  7645.     const delay_type = document.getElementById("typeSelect").value;
  7646.     let item_id = document.getElementById("secondSelect").value;
  7647.     const days = parseInt(document.getElementById("daysInput").value, 10);
  7648.     const reason = document.getElementById("reasonInput").value;
  7649.  
  7650.     if (!delay_type || !item_id || isNaN(days) || !reason.trim()) {
  7651.         alert("Please fill in all fields.");
  7652.         return;
  7653.     }
  7654.  
  7655.     if (delay_type !== "project") {
  7656.         item_id = parseInt(item_id, 10);
  7657.         if (isNaN(item_id)) {
  7658.             alert("Please select a valid item.");
  7659.             return;
  7660.         }
  7661.     }
  7662.  
  7663.     console.log({
  7664.         delay_type,
  7665.         item_id,
  7666.         days,
  7667.         reason
  7668.     });
  7669.  
  7670.     try {
  7671.         const res = await fetch("/project/api/add-delay/", {
  7672.             method: "POST",
  7673.             headers: {
  7674.                 "Content-Type": "application/json",
  7675.                 "X-CSRFToken": "{{ csrf_token }}"
  7676.             },
  7677.             credentials: "include",
  7678.             body: JSON.stringify({ delay_type, item_id, days, reason })
  7679.         });
  7680.  
  7681.         let data;
  7682.         try {
  7683.             data = await res.json();
  7684.         } catch (e) {
  7685.             // If JSON parsing fails, show generic error
  7686.             alert("Server error: Unable to process response");
  7687.             return;
  7688.         }
  7689.  
  7690.         // Check if request was successful
  7691.         if (res.ok) {
  7692.             // Success case
  7693.             alert(data.message);
  7694.             document.getElementById("delayModal").style.display = "none";
  7695.         } else {
  7696.             // Error case - display the specific error message from Django
  7697.             const errorMessage = data.error || data.message || "Failed to add delay.";
  7698.             alert(errorMessage);
  7699.         }
  7700.  
  7701.     } catch (err) {
  7702.         console.error(err);
  7703.         alert("Network error: Unable to connect to server");
  7704.     }
  7705. }
  7706.  
  7707.             // window.onload=()=>{
  7708.             //     document.querySelector('.sort-date').click()
  7709.             // }
  7710.         </script>
  7711.  
  7712.  
  7713. </body>
  7714.  
Advertisement
Add Comment
Please, Sign In to add comment