Keka Log Duration by Jp

try to take over the world

目前為 2024-03-01 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Keka Log Duration by Jp
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  try to take over the world
// @author       You
// @match        https://ezeetechnosys.keka.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=keka.com
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    'use strict';
    const channel = new BroadcastChannel('keka-duration');
    let fistDuration;
    let secondDuration;
    let thirdDuration;
    let fourthDuration;
    let fifthDuration;
    function parseTime(timeStr) {
        const parts = timeStr.split(':');
        return parseInt(parts[0]) * 3600000 + parseInt(parts[1]) * 60000 + parseInt(parts[2]) * 1000;
    }
    let lastLogIndex=0;

    function calculateTotalDuration(duration1Str, duration2Str, duration3Str, duration4Str, duration5Str) {
        // Initialize total hours and minutes
        let totalHours = 0;
        let totalMinutes = 0;

        // Array of all duration strings
        const durations = [duration1Str, duration2Str, duration3Str, duration4Str, duration5Str];

        // Loop through each duration string
        durations.forEach(durationStr => {
            if (durationStr) { // Check if the duration string is not empty
                const [hours, minutes] = durationStr.match(/\d+/g).map(Number);
                totalHours += hours;
                totalMinutes += minutes;
            }
        });

        // Add overflow from minutes to hours
        totalHours += Math.floor(totalMinutes / 60);
        totalMinutes = totalMinutes % 60;

        // Format the total duration string
        const totalDurationStr = `${totalHours} Hr ${totalMinutes} Min`;

        return totalDurationStr;
    }


    function calculateDuration(startTimeSpan, endTimeSpan) {
        const startTimeStr = startTimeSpan.textContent.trim();
        const endTimeStr = endTimeSpan.textContent.trim();

        // If end time is empty, use current time
        const endTime = endTimeStr != "MISSING" ? endTimeStr : new Date().toLocaleTimeString('en-US', { hour12: true });
        console.log("TIMES", startTimeStr, endTime);
        // Parse time strings into Date objects
        const startTime = new Date(`2023-12-27 ${startTimeStr}`); // Assuming today's date
        const endTimeDate = new Date(`2023-12-27 ${endTime}`);

        // Calculate duration in milliseconds
        const durationMillis = endTimeDate.getTime() - startTime.getTime();

        // Convert milliseconds to hours and minutes
        const durationHours = Math.floor(durationMillis / (3600 * 1000));
        const durationMinutes = Math.floor((durationMillis % (3600 * 1000)) / (60 * 1000));

        // Formatted duration string
        const durationStr = `${durationHours} Hr ${durationMinutes} Min`;

        return durationStr;
    }

    function watchForModals() {
        const modals = document.querySelectorAll('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div');
        console.log("Modals", modals)

        modals.forEach(modal => {

            const modalsArray = Array.from(modals);
            const dayIndex = modalsArray.indexOf(modal) + 1; // Determine the day index (1, 2, or 3)

            const displaySpanXPath = `/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div/div[1]/span[1]`;
            const displaySpan = document.evaluate(
                displaySpanXPath,
                modal,
                null,
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                null
            ).snapshotItem(0);

            const startTimeSpan = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[1]/div[1]/div[2]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const endTimeSpan = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[1]/div[1]/div[3]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const startTimeSpan1 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[2]/div[1]/div[2]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const endTimeSpan1 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[2]/div[1]/div[3]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const startTimeSpan2 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[3]/div[1]/div[2]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const endTimeSpan2 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[3]/div[1]/div[3]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const startTimeSpan3 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[4]/div[1]/div[2]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const endTimeSpan3 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[4]/div[1]/div[3]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const startTimeSpan4 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[5]/div[1]/div[2]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;

            const endTimeSpan4 = document.evaluate(
                '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[5]/div[1]/div[3]/span[2]',
                modal,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;




            

            if (startTimeSpan && endTimeSpan) {
                const durationStr = calculateDuration(startTimeSpan, endTimeSpan);
                fistDuration = durationStr
                const durationDisplaySpan = document.querySelector('.d-flex.align-items-center.ml-10');

                window.postMessage({ type: 'duration', value: durationStr }, '*');
                console.log("POSTED-DURATION")
                // Check for existing duration span:
                const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-1');
                if (!existingDurationSpan) {
                    // Create span only if it doesn't exist
                    const durationSpan = document.createElement('span');
                    durationSpan.classList.add('duration-span-1'); // Add class for identification
                    durationSpan.textContent = durationStr;
                    durationSpan.style.fontWeight = 'bold';
                    durationSpan.style.paddingLeft = '17px';
                    durationSpan.style.color = 'darkred';
                    durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
                } else {
                    console.log("Duration span already exists, skipping creation.");
                }

                var parentDivs = document.querySelectorAll('div.mb-30.ng-untouched.ng-pristine.ng-valid');
                if (parentDivs.length > 1) {
                    // Targeting the second div as per your requirement
                    var targetDiv = parentDivs[1];
                    var pElement = targetDiv.querySelector('p.text-large'); // Assuming the span is the one you've added
                    var spanElement = document.createElement('span');
                    // Texts array for the morphing effect
                    const texts = ["Log Duration", "    By @Jp"];
                    let textIndex = 0;

                    // Function to update the text with a morphing effect
                    function updateText() {
                        const nextText = texts[textIndex % texts.length];
                        textIndex++;

                        // Applying a fade-out effect
                        spanElement.style.opacity = '0';
                        spanElement.style.transition = 'opacity 0.5s ease-out';

                        // After fade-out, change the text and fade it back in
                        setTimeout(() => {
                            spanElement.textContent = nextText;

                            // Applying blur during transition
                            spanElement.style.filter = 'blur(2px)';
                            spanElement.style.opacity = '1';
                            spanElement.style.transition = 'opacity 0.5s ease-in, filter 0.5s ease';

                            // Removing blur after a moment
                            setTimeout(() => {
                                spanElement.style.filter = 'none';
                            }, 500); // Match the transition time
                        }, 500); // Wait for the fade-out to complete
                    }

                    // Starting the text update process
                    spanElement.style.fontWeight = 'bold';
                    spanElement.style.color = 'rgb(0, 123, 255)';
                    spanElement.style.padding = '5px';
                    spanElement.style.borderRadius = '5px';
                    spanElement.style.fontSize = '16px';
                    spanElement.style.marginLeft = '262px';
                    spanElement.textContent = texts[textIndex % texts.length];
                    textIndex++;
                    pElement.appendChild(spanElement);
                    setInterval(updateText, 2000);
                }
            }

            if (startTimeSpan1 && endTimeSpan1) {
                lastLogIndex = 1;
                console.log("11111111--11111", startTimeSpan1, endTimeSpan1)
                const durationStr = calculateDuration(startTimeSpan1, endTimeSpan1);
                secondDuration = durationStr;
                const durationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(2) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid > div.d-flex.align-items-center.ml-10');
                console.log("durationDisplaySpan", durationDisplaySpan)

                // Check for existing duration span:
                const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-2');
                if (!existingDurationSpan) {
                    // Create span only if it doesn't exist
                    const durationSpan = document.createElement('span');
                    durationSpan.classList.add('duration-span-2'); // Add class for identification
                    durationSpan.textContent = durationStr;
                    durationSpan.style.fontWeight = 'bold';
                    durationSpan.style.paddingLeft = '17px';
                    durationSpan.style.color = 'darkred';
                    durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
                } else {
                    console.log("Duration span already exists, skipping creation.");
                }

            }
            if (startTimeSpan2 && endTimeSpan2) {
                lastLogIndex = 2;
                console.log("11111111--11111", startTimeSpan2, endTimeSpan2)
                const durationStr = calculateDuration(startTimeSpan2, endTimeSpan2);
                thirdDuration = durationStr;
                const durationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(3) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid > div.d-flex.align-items-center.ml-10');
                console.log("durationDisplaySpan", durationDisplaySpan)

                // Check for existing duration span:
                const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-3');
                if (!existingDurationSpan) {
                    // Create span only if it doesn't exist
                    const durationSpan = document.createElement('span');
                    durationSpan.classList.add('duration-span-3'); // Add class for identification
                    durationSpan.textContent = durationStr;
                    durationSpan.style.fontWeight = 'bold';
                    durationSpan.style.paddingLeft = '17px';
                    durationSpan.style.color = 'darkred';
                    durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
                } else {
                    console.log("Duration span already exists, skipping creation.");
                }

            }
            if (startTimeSpan3 && endTimeSpan3) {
                lastLogIndex = 3;
                console.log("11111111--11111", startTimeSpan3, endTimeSpan3)
                const durationStr = calculateDuration(startTimeSpan3, endTimeSpan3);
                fourthDuration = durationStr;
                const durationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(3) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid > div.d-flex.align-items-center.ml-10');
                console.log("durationDisplaySpan", durationDisplaySpan)

                // Check for existing duration span:
                const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-3');
                if (!existingDurationSpan) {
                    // Create span only if it doesn't exist
                    const durationSpan = document.createElement('span');
                    durationSpan.classList.add('duration-span-3'); // Add class for identification
                    durationSpan.textContent = durationStr;
                    durationSpan.style.fontWeight = 'bold';
                    durationSpan.style.paddingLeft = '17px';
                    durationSpan.style.color = 'darkred';
                    durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
                } else {
                    console.log("Duration span already exists, skipping creation.");
                }

            }
            if (startTimeSpan4 && endTimeSpan4) {
                lastLogIndex = 4;
                console.log("11111111--11111", startTimeSpan4, endTimeSpan4)
                const durationStr = calculateDuration(startTimeSpan4, endTimeSpan4);
                fifthDuration = durationStr;
                const durationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(4) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid > div.d-flex.align-items-center.ml-10');
                console.log("durationDisplaySpan", durationDisplaySpan)

                // Check for existing duration span:
                const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-4');
                if (!existingDurationSpan) {
                    // Create span only if it doesn't exist
                    const durationSpan = document.createElement('span');
                    durationSpan.classList.add('duration-span-4'); // Add class for identification
                    durationSpan.textContent = durationStr;
                    durationSpan.style.fontWeight = 'bold';
                    durationSpan.style.paddingLeft = '17px';
                    durationSpan.style.color = 'darkred';
                    durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
                } else {
                    console.log("Duration span already exists, skipping creation.");
                }

            }
            if(lastLogIndex) {

            const totaldurationDisplaySpan = document.querySelector(`body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(${lastLogIndex+1}) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid`);
            console.log(fistDuration, secondDuration, "#################")
            const total = calculateTotalDuration(fistDuration, secondDuration,thirdDuration,fourthDuration,fifthDuration);
            console.log("total", total)

            // Check for existing total duration span:
            const existingTotalDurationSpan = totaldurationDisplaySpan.querySelector('.total-duration-span');
            if (!existingTotalDurationSpan) {
                // Create span only if it doesn't exist
                const TotaldurationSpan = document.createElement('span'); // Added closing parenthesis
                TotaldurationSpan.classList.add('total-duration-span'); // Add class for identification
                TotaldurationSpan.textContent = total;
                TotaldurationSpan.style.fontWeight = 'bold';
                // TotaldurationSpan.style.paddingLeft = '17px';
                TotaldurationSpan.style.color = '#0600ff';
                TotaldurationSpan.style.float = 'right';
                TotaldurationSpan.style.padding = '5px';
                TotaldurationSpan.style.background = 'lightblue';
                TotaldurationSpan.style.marginRight = '150px';
                TotaldurationSpan.style.borderRadius = '5px';
                TotaldurationSpan.style.borderTop = '3px solid #888'
                totaldurationDisplaySpan.insertAdjacentElement('afterend', TotaldurationSpan);

            }
            }



        })
    };

    


    const observer = new MutationObserver(mutations => {
        console.log("Observing.....")
        const modalTriggerElements = document.querySelectorAll('employee-attendance-list-view .attendance-logs-row');
        modalTriggerElements.forEach(element => {
            element.addEventListener('click', watchForModals);
        });
    });

    observer.observe(document.body, { childList: true, subtree: false });

})(); // Closed parenthesis for the immediately invoked function expression