plugins_Waivers_assets_js_controllers_retention-policy-input-controller.js

import { Controller } from "@hotwired/stimulus"

/**
 * Retention Policy Input Controller
 * 
 * Provides a structured interface for retention policy configuration with real-time preview.
 * Replaces simple JSON textarea with user-friendly inputs (years, months, days, anchor).
 * 
 * Targets:
 * - anchorSelect: The anchor point selection (gathering_end_date, upload_date, permanent)
 * - yearsInput: Years input field
 * - monthsInput: Months input field
 * - daysInput: Days input field
 * - durationSection: Container for duration inputs (hidden when anchor=permanent)
 * - preview: Preview text showing formatted policy
 * - hiddenInput: Hidden input that stores the JSON value for form submission
 * 
 * Actions:
 * - updatePreview: Updates preview text and hidden JSON field when any input changes
 */
class RetentionPolicyInputController extends Controller {
    static targets = [
        "anchorSelect",
        "yearsInput",
        "monthsInput",
        "daysInput",
        "durationSection",
        "preview",
        "hiddenInput"
    ]

    /**
     * Initialize controller
     */
    connect() {
        // Initialize preview on load
        this.updatePreview()
    }

    /**
     * Update preview text and hidden JSON field
     * Called whenever any input changes
     */
    updatePreview() {
        const anchor = this.anchorSelectTarget.value
        const years = parseInt(this.yearsInputTarget.value) || 0
        const months = parseInt(this.monthsInputTarget.value) || 0
        const days = parseInt(this.daysInputTarget.value) || 0

        // Show/hide duration section based on anchor
        if (anchor === 'permanent') {
            this.durationSectionTarget.style.display = 'none'
        } else {
            this.durationSectionTarget.style.display = 'block'
        }

        // Build JSON structure
        let policy = {
            anchor: anchor
        }

        // Add duration if not permanent
        if (anchor !== 'permanent') {
            policy.duration = {}
            if (years > 0) policy.duration.years = years
            if (months > 0) policy.duration.months = months
            if (days > 0) policy.duration.days = days
        }

        // Update hidden input with JSON
        this.hiddenInputTarget.value = JSON.stringify(policy)

        // Update preview text
        this.previewTarget.textContent = this.formatPreviewText(anchor, years, months, days)
    }

    /**
     * Format preview text in human-readable format
     * 
     * @param {string} anchor - The anchor point
     * @param {number} years - Years duration
     * @param {number} months - Months duration
     * @param {number} days - Days duration
     * @returns {string} Formatted preview text
     */
    formatPreviewText(anchor, years, months, days) {
        // Handle permanent retention
        if (anchor === 'permanent') {
            return 'Permanent retention (never expires)'
        }

        // Build duration parts
        const parts = []
        if (years > 0) {
            parts.push(`${years} ${years === 1 ? 'year' : 'years'}`)
        }
        if (months > 0) {
            parts.push(`${months} ${months === 1 ? 'month' : 'months'}`)
        }
        if (days > 0) {
            parts.push(`${days} ${days === 1 ? 'day' : 'days'}`)
        }

        // If no duration specified, show warning
        if (parts.length === 0) {
            return '⚠️ No duration specified'
        }

        // Format anchor point text
        const anchorText = anchor === 'gathering_end_date' 
            ? 'from gathering end date' 
            : 'from upload date'

        return `${parts.join(', ')} ${anchorText}`
    }

    /**
     * Parse existing JSON value into form fields
     * Called when editing an existing waiver type
     * 
     * @param {string} jsonValue - JSON string from database
     */
    parseJson(jsonValue) {
        try {
            const policy = JSON.parse(jsonValue)
            
            // Set anchor
            if (policy.anchor) {
                this.anchorSelectTarget.value = policy.anchor
            }

            // Set duration values
            if (policy.duration) {
                this.yearsInputTarget.value = policy.duration.years || 0
                this.monthsInputTarget.value = policy.duration.months || 0
                this.daysInputTarget.value = policy.duration.days || 0
            }

            // Update preview
            this.updatePreview()
        } catch (e) {
            console.error('Failed to parse retention policy JSON:', e)
            this.previewTarget.textContent = '⚠️ Invalid JSON format'
        }
    }

    /**
     * Validate inputs before form submission
     * 
     * @returns {boolean} True if valid, false otherwise
     */
    validate() {
        const anchor = this.anchorSelectTarget.value
        
        // Permanent is always valid
        if (anchor === 'permanent') {
            return true
        }

        // Check that at least one duration value is specified
        const years = parseInt(this.yearsInputTarget.value) || 0
        const months = parseInt(this.monthsInputTarget.value) || 0
        const days = parseInt(this.daysInputTarget.value) || 0

        if (years === 0 && months === 0 && days === 0) {
            alert('Please specify at least one duration value (years, months, or days)')
            return false
        }

        return true
    }
}

// Add to global controllers registry
if (!window.Controllers) {
    window.Controllers = {};
}
window.Controllers["retention-policy-input"] = RetentionPolicyInputController;