Assign Interaction: autofill

Infer information for the interaction you're assigning.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Вам потребуется установить расширение, например Tampermonkey или Violentmonkey, чтобы установить этот скрипт.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==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);
})();