pia autofill

Automatically fills and saves application data using separate Fill and Save buttons.

// ==UserScript==
// @name         pia autofill
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Automatically fills and saves application data using separate Fill and Save buttons.
// @author       Misaka_ZeroTwo
// @match        https://va.pia.jp/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

// --- CONFIGURATION ---
const STORAGE_KEY = 'piaAutofillData';

// === DEFAULT USER DATA (Used if no data in localStorage) ===
// NOTE: Use a unique variable name to avoid confusion with the loaded data
const defaultFormData = {
    // お客様情報 (Customer Info)
    cstmr_lnm: '山田',      // 姓 (Last Name/Family Name)
    cstmr_fnm: '太郎',      // 名 (First Name/Given Name)
    cstmr_lkn: 'ヤマダ',    // セイ (Last Name Katakana)
    cstmr_fkn: 'タロウ',    // メイ (First Name Katakana)

    // 性別 (Gender): '2': Female, '1': Male, '8': Others, '9': Prefer not answer
    sex_typ: '1',

    // 生年月日 (Date of Birth) - Use options from the select menus
    birth_yyyy: '1990',
    birth_mm: '05',
    birth_dd: '25',

    // 電話番号 (Phone Number)
    telno1: '090',
    telno2: '1234',
    telno3: '5678',

    // Email Address
    email: '[email protected]',

    // Address (All address fields use 'cmnt' names)
    postcode1: '221',       // 郵便番号上3桁 - cmnt01
    postcode2: '0013',      // 郵便番号下4桁 - cmnt02
    prefecture: '神奈川県',   // 都道府県 - cmnt11 (MUST MATCH AN <option> VALUE)
    city: '横浜市神奈川区',         // 市町村 - cmnt12
    district: '新子安',   // 町名 - cmnt13
    street: '4-5-6'         // 丁目・番地・号 - cmnt14
};

// =================================================================
// --- HELPER FUNCTIONS ---
// =================================================================

/**
 * Helper function to set value and trigger change events on form elements.
 */
const setInputValue = (selector, value) => {
    const element = document.querySelector(selector);
    if (element) {
        element.value = value;
        // Crucial for form validation to think a user typed the info
        ['input', 'change'].forEach(eventType => {
            const event = new Event(eventType, { bubbles: true });
            element.dispatchEvent(event);
        });
        return true;
    }
    return false;
};

/**
 * Helper function to get value from a form element.
 */
const getInputValue = (selector, isRadio = false) => {
    if (isRadio) {
        // For radio buttons, we want the value of the CHECKED one
        const checkedRadio = document.querySelector(`${selector}:checked`);
        return checkedRadio ? checkedRadio.value : '';
    }
    const element = document.querySelector(selector);
    return element ? element.value : '';
};


// =================================================================
// --- LOCALSTORAGE & DATA MANAGEMENT ---
// =================================================================

/**
 * Loads form data from localStorage, falling back to default data if empty.
 * @returns {Object} The form data.
 */
function loadFormData() {
    try {
        const storedData = localStorage.getItem(STORAGE_KEY);
        if (storedData) {
            console.log("Data loaded from localStorage.");
            return JSON.parse(storedData);
        }
    } catch (e) {
        console.error("Error loading from localStorage:", e);
    }
    console.log("No data found in localStorage. Using default data.");
    return defaultFormData;
}

/**
 * Saves the provided data into localStorage.
 * @param {Object} data - The data object to save.
 */
function saveFormData(data) {
    try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
        console.log("✅ Form data saved to localStorage.");
        alert("✅ Current form data saved successfully!");
    } catch (e) {
        console.error("Error saving to localStorage:", e);
        alert("🚨 Failed to save data. Please check the console.");
    }
}


// =================================================================
// --- FILL & RETRIEVE LOGIC ---
// =================================================================

/**
 * Fills the form using the provided data.
 * @param {Object} data - The data object to fill the form with.
 */
function fillForm(data) {
    console.clear();
    console.log("🚀 Starting form fill...");

    // Existing Fields (cstmr prefix)
    setInputValue('input[name="cstmr_lnm"]', data.cstmr_lnm);
    setInputValue('input[name="cstmr_fnm"]', data.cstmr_fnm);
    setInputValue('input[name="cstmr_lkn"]', data.cstmr_lkn);
    setInputValue('input[name="cstmr_fkn"]', data.cstmr_fkn);
    setInputValue('select[name="birth_yyyy"]', data.birth_yyyy);
    setInputValue('select[name="birth_mm"]', data.birth_mm);
    setInputValue('select[name="birth_dd"]', data.birth_dd);
    setInputValue('input[name="telno1"]', data.telno1);
    setInputValue('input[name="telno2"]', data.telno2);
    setInputValue('input[name="telno3"]', data.telno3);

    // Radio Button (Sex/Gender)
    const sexRadio = document.querySelector(`input[name="sex_typ"][value="${data.sex_typ}"]`);
    if (sexRadio) {
        sexRadio.checked = true;
        sexRadio.dispatchEvent(new Event('change', { bubbles: true }));
    }

    // Email Address (ml_addr and ml_addr_cnfm)
    setInputValue('input[name="ml_addr"]', data.email);
    setInputValue('input[name="ml_addr_cnfm"]', data.email); // Fills confirm email too!

    // Postcode (cmnt01 and cmnt02)
    setInputValue('input[name="cmnt01"]', data.postcode1);
    setInputValue('input[name="cmnt02"]', data.postcode2);

    // Address (cmnt11, cmnt12, cmnt13, and cmnt14)
    setInputValue('select[name="cmnt11"]', data.prefecture); // Prefecture (Select dropdown)
    setInputValue('input[name="cmnt12"]', data.city);        // City/Ward (Text input)
    setInputValue('input[name="cmnt13"]', data.district);    // District (Text input)
    setInputValue('input[name="cmnt14"]', data.street);      // Street/Apartment (Text input - cmnt14)

    console.log("✅ Autofill script completed. You can now edit and save the form data.");
}

/**
 * Retrieves the current form data from the page fields.
 * @returns {Object} The data object containing current field values.
 */
function retrieveForm() {
    return {
        cstmr_lnm: getInputValue('input[name="cstmr_lnm"]'),
        cstmr_fnm: getInputValue('input[name="cstmr_fnm"]'),
        cstmr_lkn: getInputValue('input[name="cstmr_lkn"]'),
        cstmr_fkn: getInputValue('input[name="cstmr_fkn"]'),
        sex_typ: getInputValue('input[name="sex_typ"]', true), // isRadio = true
        birth_yyyy: getInputValue('select[name="birth_yyyy"]'),
        birth_mm: getInputValue('select[name="birth_mm"]'),
        birth_dd: getInputValue('select[name="birth_dd"]'),
        telno1: getInputValue('input[name="telno1"]'),
        telno2: getInputValue('input[name="telno2"]'),
        telno3: getInputValue('input[name="telno3"]'),
        email: getInputValue('input[name="ml_addr"]'), // Using the main email field
        postcode1: getInputValue('input[name="cmnt01"]'),
        postcode2: getInputValue('input[name="cmnt02"]'),
        prefecture: getInputValue('select[name="cmnt11"]'),
        city: getInputValue('input[name="cmnt12"]'),
        district: getInputValue('input[name="cmnt13"]'),
        street: getInputValue('input[name="cmnt14"]'),
    };
}


// =================================================================
// --- BUTTON LOGIC AND INITIALIZATION ---
// =================================================================

const buttonContainer = document.createElement('div');
buttonContainer.style.cssText = `
    position: fixed;
    top: 10px;
    right: 10px;
    z-index: 9999;
    display: flex; /* Use flexbox to align buttons */
    gap: 10px;    /* Space between buttons */
`;

const baseButtonStyle = `
    padding: 10px 15px;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    font-weight: bold;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
`;

// 1. Create the FILL button
const fillButton = document.createElement('button');
fillButton.id = 'autofill-script-fill-button';
fillButton.textContent = '🚀 Autofill Form';
fillButton.style.cssText = baseButtonStyle + `background-color: #007bff;`; // Blue

fillButton.addEventListener('click', () => {
    // 1. Load data from storage (or default)
    const data = loadFormData();

    // 2. Fill the form
    fillForm(data);

    // 3. Show the save button
    saveButton.style.display = 'block';
});

// 2. Create the SAVE button
const saveButton = document.createElement('button');
saveButton.id = 'autofill-script-save-button';
saveButton.textContent = '💾 Save Edits';
saveButton.style.cssText = baseButtonStyle + `background-color: #28a745;`; // Green

saveButton.addEventListener('click', () => {
    // 1. Retrieve current data from form fields
    const currentData = retrieveForm();

    // 2. Save the retrieved data to storage
    saveFormData(currentData);
});

// 3. Initial state: Hide the save button
saveButton.style.display = 'none';

// 4. Add buttons to the container
buttonContainer.appendChild(fillButton);
buttonContainer.appendChild(saveButton);

// 5. Add the container to the page body
document.body.appendChild(buttonContainer);

console.log('Autofill and Save buttons added. Click "🚀 Autofill Form" first. The "💾 Save Edits" button will appear after filling.');