Assign Interaction: autofill

Infer information for the interaction you're assigning.

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey, Greasemonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

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