Assign Interaction: autofill

Infer information for the interaction you're assigning.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

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

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Assign Interaction: autofill
// @namespace    https://github.com/nate-kean/
// @version      2026.5.10
// @description  Infer information for the interaction you're assigning.
// @author       Nate Kean
// @match        https://jamesriver.fellowshiponego.com/members/view/*
// @match        https://jamesriver.fellowshiponego.com/members/family/*
// @match        https://jamesriver.fellowshiponego.com/members/timeline/*
// @match        https://jamesriver.fellowshiponego.com/members/giving/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=fellowshiponego.com
// @require      https://update.greasyfork.org/scripts/559387/1730426/getRelativeWeekday.js
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    const actionSpan = document
        .querySelector("#aid") // TODO: this could be condensed in to one, smarter selector
        .parentElement
        .querySelector(".chosen-container > a > span");
    const completeByDateInput = document.querySelector("#completeByDate");
    const today = new Date();

    const instructionsInput = document.querySelector("#instructions");

    const firstName = () => document.querySelector(".pg-title").textContent.trim().split(" ")[0];

    function campus() {
        let campusName;
        const additionalDetailsEntries = document.querySelectorAll(".other-panel > .panel-body > .info-right-column > .other-details");
        for (const entry of additionalDetailsEntries) {
            if (entry.textContent.includes("Campus")) {
                return entry.textContent.trim().split(" ")[0];
            }
        }
        return "__";
    }

    function firstVisitDate() {
        let campusName;
        const additionalDetailsEntries = document.querySelectorAll(".date-panel > .panel-body > .info-right-column > .date-details");
        for (const entry of additionalDetailsEntries) {
            if (entry.textContent.includes("First Visit Date")) {
                return entry.textContent.trim();
            }
        }
        return "__";
    }

    function friday() {
        // This Friday on Sun, Mon, Tue, Wed, Sat; next Friday on Thu, Fri
        const fridayDate = getRelativeWeekday(today, DateDir.THIS, Day.FRIDAY, false);
        if ([Day.THURSDAY, Day.FRIDAY].includes(today.getDay())) {
            // If it's already Thursday or Friday, make it next Friday
            fridayDate.setDate(fridayDate.getDate() + 7);
        }
        return fridayDate;
    }

    function whose() {
        // Determine possessive adjective to use based on gender
        for (const p of document.querySelectorAll(".family-name > p")) {
            switch (p.textContent) {
                case "Male":
                    return "his";
                case "Female":
                    return "her";
            }
        }
        return "their";
    }

    function familyName() {
        // Scrape or request own name and spouse's name, if applicable
        const path = window.location.pathname.split("/");
        const page = path.at(-2);
        const uid = path.at(-1);
        switch (page) {
            case "view": {
                const familyMembers = document.querySelectorAll(".family-panel .family-item .family-item-details");

                const primary = familyMembers[0];
                const primaryName = primary.querySelector("a").textContent.trim().split(" ")[0];

                const spouse = familyMembers[1];
                if (spouse === undefined) return primaryName;
                const role = spouse.querySelector("h5").textContent.trim();
                if (role === "Wife" || role === "Partner") {
                    const spouseName = spouse.querySelector("a").textContent.trim().split(" ")[0];
                    return `${primaryName} & ${spouseName}`;
                }
                return primaryName;
            }
            case "family":
                // TODO: scrape another way
                return "__";
                //break;
            default:
                // TODO: request
                return "__";
        }
    }


    function connectionPoint() {
        return "__";
    }


    function experienceType() {
        // TODO: the one with the latest date
        return "__";
    }


    function generateAutofillContent(actionName) {
        switch (actionName) {
            case "New Visitor Connections Follow-Up":
                return {
                    date: today,
                    instructions: `${campus().toUpperCase()}/TEXT - Please send ${familyName()} a welcome text by 5pm. Thank you!`,
                };
            case "New Visitor Follow-Up: Cookie Visit":
                return {
                    date: today,
                    instructions: `COOKIE VISIT • ${connectionPoint()} • First visited ${firstVisitDate()}`,
                };
            case "New Visitor Follow- Up: Phone Call":
                return {
                    date: friday(),
                    instructions: `PHONE CALL • ${connectionPoint()} • First visited ${firstVisitDate()}`,
                };
            case "Altar Follow-Up": {
                return {
                    date: friday(),
                    instructions: `Please follow up with ${firstName()} regarding ${whose()} ${experienceType()} this week. Thank you!`,
                };
            }
            case "Discipleship":
                return {
                    date: getRelativeWeekday(today, DateDir.THIS, Day.TUESDAY, false),
                    instructions: `Please follow up with ${firstName()} regarding ${whose()} baptism this week. Thank you!`,
                }
        }
        return {
            date: null,
            instructions: null,
        };
    }


    function formatDate(date) {
        const month = String(date.getMonth() + 1).padStart(2, "0");
        const day = String(date.getDate()).padStart(2, "0");
        const year = date.getFullYear();
        return `${month}/${day}/${year}`;
    }


    function onMutation(records) {
        const content = generateAutofillContent(actionSpan.textContent);
        if (completeByDateInput.value === "" && content.date !== null) {
            completeByDateInput.value = formatDate(content.date);
        }
        if (instructionsInput.value === "" && content.instructions !== null) {
            instructionsInput.value = content.instructions;
        }
    }


    const observer = new MutationObserver(onMutation);
    const options = {
        subtree: false,
        childList: true,
        attributes: false,
        characterData: true,
        characterDataOldValue: false,
    };
    observer.observe(actionSpan, options);
})();