Jake Vanderwerf
2026-08-28 a9654f00c8fbc9934289d761843ddd071025013f
inc/users/UserSettings.php
@@ -1,633 +1,635 @@
<?php
namespace JVBase\users;
use JVBase\JVB;
use JVBase\registry\ContentRegistry;
//use JVBase\registry\ContentRegistry;
if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}
class UserSettings extends ContentRegistry
{
    protected array $fields;
    protected array $sections = [
        'account'   => [
            'title'         => 'Account',
            'icon'          => 'settings',
        ],
        'notifications' => [
            'title'         => 'Notifications',
            'icon'          => 'email'
        ],
        'newsletter' => [
            'title'         => 'Newsletter',
            'icon'          => 'logo'
        ],
        'invitations'    => [
            'title'        => 'Invite Artists',
            'icon'        => 'new-user',
        ]
    ];
    protected array $frequency = [
        'never'     => 'Never',
        'daily'     => 'Daily',
        'weekly'    => 'Weekly',
        'monthly'   => 'Monthly',
    ];
    public function initType():void
    {
        $this->object_type = 'user';
        $this->userFields();
    }
    public function getFields():array
    {
        return $this->fields;
    }
    public function getSections():array
    {
        return $this->sections;
    }
    public function userFields():void
    {
        $this->fields = [
            'display_name'  => [
                'type'  => 'text',
                'label' => 'Name',
                'description'   => 'Optional. Only used if you allow artists to see your info when you favourite them.',
                'default'   => '',
                'section'   => 'account',
                'role'      => ['ei_enthusiast']
            ],
            'user_email'    => [
                'type'  => 'email',
                'label' => 'Email',
                'description'   => 'Required for any notifications you subscribe to.',
                'default'   => '',
                'section'   => 'account',
                'role'      => ['ei_enthusiast']
            ],
            'city'      => [
                'type'  => 'text',
                'label' => 'City',
                'description'   => 'Optional. Just helps us know where people who use this site are located.',
                'default'   => '',
                'section'   => 'account',
                'role'      => ['ei_enthusiast']
            ],
            'notify'    => [
                'type'  => 'true_false',
                'label' => 'Notify artists when you favourite their work',
                'description'   => 'If you select this, artists will see your name when you favourite their work, else they will just get an anonymous notification.',
                'default'   => false,
                'section'   => 'account',
            ],
            'dark_mode'    => [
                'type'  => 'true_false',
                'label' => 'Dark Mode',
                'default'   => false,
            ],
            'email_digest'  => [
                'type'      => 'radio',
                'label'     => 'Email Summary Frequency',
                'options'   => $this->frequency,
                'default'   => 'never',
                'section'       => 'notifications'
            ],
            'digest_override'   => [
                'type'  => 'true_false',
                'label' => 'Apply to all notifications',
                'description'   => 'Override individual notification settings and apply this frequency to all your notifications',
                'default'     => false,
                'section'       => 'notifications'
            ],
            'notifications' => [
                'type'      => 'callback',
                'callback'  => 'renderNotifications',
                'label'     => 'Notifications',
                'section'   => 'notifications',
                'default'   => '',
            ],
            'site_updates'  => [
                'type'  => 'true_false',
                'label' => 'Site Updates',
                'description' => 'Get notified when new features are added to edmonton.ink',
                'default'   => false,
                'section'   => 'account',
            ],
            'newsletter'    => [
                'type'  => 'true_false',
                'label' => 'Newsletter',
                'description'   => 'Sign up for our monthly-ish newsletter, featuring upcoming events, featured artists, new artists, and their work.',
                'default'   => false,
                'section'   => 'newsletter',
            ],
            'owner_of'    => [
                'type' => 'taxonomy',
                'label'    => __('Owner of', 'jvb'),
                'taxonomy_type' => 'reference',
                'taxonomy' => BASE. 'shop',
                'quickEdit'    => true,
                'default'    => '',
            ],
            'manager_of'    => [
                'type' => 'taxonomy',
                'label'    => __('Manager of', 'jvb'),
                'taxonomy_type' => 'reference',
                'taxonomy' => BASE. 'shop',
                'hidden'    => true,
                'default'    => '',
            ],
            'invitations'    => [
                'type'    => 'callback',
                'callback'    => 'handleInvitationsManagement',
                'section'    => 'invitations',
                'label'        => __('Invite Artists', 'jvb'),
                'role'      => ['ei_artist']
            ],
        ];
    }
    /**
     * Render custom notification preferences UI
     * @param int $user_id
     *
     * @return string
     */
    public function renderNotifications(int $user_id):string
    {
        $favourites = $this->getUserFavourites($user_id);
        $preferences = $this->getUserNotificationPreferences($user_id);
        global $notify;
        ob_start();
        ?>
        <div class="notification-preferences">
            <?php foreach ($favourites as $type => $items) : ?>
                <details class="notification-group">
                    <summary class="notification-group-header row btw">
                        <span class="type-label"><?=jvbIcon('heart', ['style' => 'fill'])?> <?= $notify[$type] ?></span>
                        <span class="type-count">( <?= count($items); ?> )</span>
                    </summary>
                    <?php if (!empty($items)) : ?>
                        <table class="notification-table">
                            <thead>
                            <tr>
                                <th>Name</th>
                                <th>Frequency</th>
                            </tr>
                            </thead>
                            <tbody>
                            <?php foreach ($items as $item) : ?>
                                <?php
                                $current = isset($preferences['preferences'][$type][$item['id']])
                                    ? $preferences['preferences'][$type][$item['id']]
                                    : $preferences['default_frequency'];
                                ?>
                                <tr>
                                    <td><?= esc_html($item['name']); ?></td>
                                    <td>
                                        <div class="radio-options row">
                                            <?php foreach (['never', 'daily', 'weekly', 'monthly'] as $freq) : ?>
                                                <input type="radio"
                                                       name="notification_preferences[<?= esc_attr($type); ?>][<?= esc_attr($item['id']); ?>]"
                                                       id="<?= esc_attr("{$type}_{$item['id']}_$freq"); ?>"
                                                       value="<?= esc_attr($freq); ?>"
                                                    <?php checked($current, $freq); ?>>
                                                <label for="<?= esc_attr("{$type}_{$item['id']}_$freq"); ?>">
                                                    <?= ucfirst($freq); ?>
                                                </label>
                                            <?php endforeach; ?>
                                        </div>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                            </tbody>
                            <tfoot>
                            <tr>
                                <th>Set all <?= $type ?>s to: </th>
                                <th>
                                    <div class="radio-options row">
                                        <?php foreach (['never', 'daily', 'weekly', 'monthly'] as $freq) : ?>
                                            <input type="radio"
                                                   name="toggle-all-<?=$type?>"
                                                   id="toggle-all-<?=$type?>-<?=$freq?>"
                                                   value="<?= esc_attr($freq); ?>"
                                                class="toggle-all">
                                            <label for="toggle-all-<?=$type?>-<?=$freq?>">
                                                <?= ucfirst($freq); ?>
                                            </label>
                                        <?php endforeach; ?>
                                    </div>
                                </th>
                            </tr>
                            </tfoot>
                        </table>
                    <?php else : ?>
                        <p class="no-items">No favourites yet</p>
                    <?php endif; ?>
                </details>
            <?php endforeach; ?>
        </div>
        <script>
            function initGroupOverrides() {
                document.querySelectorAll('.toggle-all').forEach(toggle => {
                    toggle.addEventListener('change', e => {
                        e.preventDefault();
                        if(toggle.checked){
                            const table = e.target.closest('table');
                            console.log(table);
                            const value = toggle.value;
                            // Enable/disable individual controls
                            table.querySelectorAll('input[value="'+value+'"]').forEach(radio => {
                                radio.checked = true;
                            });
                        }
                    });
                });
                // Listen for changes to default frequency
                document.querySelector('input[name="digest_override"]').addEventListener('change', e=>{
                    let value = document.querySelector('input[name="email_digest"]:checked').value;
                    console.log(value);
                    document.querySelectorAll('input[value="'+value+'"]').forEach(toggle => {
                        toggle.checked = true;
                    });
                    setTimeout(function () {
                        e.target.checked = false;
                    }, 1000)
                });
            }
            initGroupOverrides();
        </script>
        <?php
        return ob_get_clean();
    }
    /**
     * Get user's favourites grouped by type
     */
    protected function getUserFavourites(int $user_id):array
    {
        global $wpdb;
        $table = $wpdb->prefix . BASE.'favourites';
        global $notify;
        global $types;
        $favourites = [];
        foreach (array_keys($notify) as $type) {
            $favourites[$type] = [];
        }
        // Fetch favourites from database
        $results = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE user_id = %d",
            $user_id
        ));
        foreach ($results as $result) {
            $type = str_replace(BASE, '', $result->type);
            if (!array_key_exists($type, $favourites)) {
                continue;
            }
            // Get proper name based on type
            switch ($types[BASE.$type]['table']) {
                case 'post':
                    $name = get_the_title($result->target_id);
                    break;
                case 'term':
                    $term = get_term($result->target_id, BASE.$type);
                    $name = $term ? html_entity_decode($term->name) : '';
                    break;
                default:
                    $name = '';
            }
            if ($name) {
                $favourites[$type][] = [
                    'id' => $result->target_id,
                    'name' => $name
                ];
            }
        }
        return $favourites;
    }
    /**
     * Get current notification preferences
     */
    protected function getNotificationPreferences(int $user_id):array
    {
        return get_user_meta($user_id, 'notification_preferences', true) ?: [];
    }
    protected function getUserNotificationPreferences(int $user_id):array
    {
        global $wpdb;
        $table = $wpdb->prefix . BASE.'notification_preferences';
//        error_log('Getting notification preferences for user: ' . $user_id);
        // Get user's preferences from the table
        $raw_preferences = $wpdb->get_results($wpdb->prepare(
            "SELECT notification_type, item_id, frequency
         FROM {$table}
         WHERE user_id = %d",
            $user_id
        ), ARRAY_A);
//        error_log('Raw preferences from database: ' . print_r($raw_preferences, true));
        // Structure the preferences
        $preferences = [];
        if (!empty($raw_preferences)) {
            foreach ($raw_preferences as $pref) {
                $type = $pref['notification_type'];
                $item_id = intval($pref['item_id']);
                $frequency = $pref['frequency'];
                if (!isset($preferences[$type])) {
                    $preferences[$type] = [];
                }
                $preferences[$type][$item_id] = $frequency;
            }
        }
        // Get default frequency
        $default_frequency = get_user_meta($user_id, BASE.'email_digest', true) ?: 'never';
//        error_log('Structured preferences: ' . print_r($preferences, true));
//        error_log('Default frequency: ' . $default_frequency);
        return [
            'preferences' => $preferences,
            'default_frequency' => $default_frequency
        ];
    }
    public function handleInvitationsManagement(int $userID):void
    {
        $name = 'artist_invite';
        ?>
        <div class="field">
            <script type="text/javascript">
                function addArtist(button){
                    let template = window.getTemplate('artistInvite');
                    let container = button.closest('.field').querySelector('.invite-artists');
                    let nameLabel = template.querySelector('label[for="invited-artist-name"]'),
                        nameInput = template.querySelector('input#invited-artist-name'),
                        emailLabel = template.querySelector('label[for="invited-artist-email"]'),
                        emailInput = template.querySelector('input#invited-artist-email'),
                        shopLabel = template.querySelector('label[for="invited-add-to-shop"]'),
                        shopInput = template.querySelector('input#invited-add-to-shop');
                    let count = container.childNodes.length;
                    console.log(container.childNodes);
                    [
                        nameLabel.htmlFor,
                        nameInput.id,
                        nameInput.name,
                        emailLabel.htmlFor,
                        emailInput.id,
                        emailInput.name,
                        shopLabel.htmlFor,
                        shopInput.id,
                        shopInput.name
                    ] =
                    [
                        `${nameLabel.getAttribute('for')}-${count}`,
                        `${nameInput.id}-${count}`,
                        `${nameInput.name}-${count}`,
                        `${emailLabel.htmlFor}-${count}`,
                        `${emailInput.id}-${count}`,
                        `${emailInput.name}-${count}`,
                        `${shopLabel.htmlFor}-${count}`,
                        `${shopInput.id}-${count}`,
                        `${shopInput.name}-${count}`
                    ];
                    container.append(template);
                }
                function removeArtist(button){
                    button.closest('.invited-artist').remove();
                }
                async function revokeInvite(button){
                    try {
                        let artist = button.closest('tr');
                        let id = artist.id;
                        const headers = {
                            'X-WP-Nonce': eiSettings.nonce,
                            'action_nonce': eiSettings.dash,
                            'Content-Type': 'application/json'
                        };
                        let body = {
                            user: eiSettings.currentUser,
                            revoke: id
                        };
                        let request = {
                            method: 'POST',
                            headers: headers,
                            body: JSON.stringify(body)
                        };
                        console.log(request);
                        const response = await fetch(`${eiSettings.api}invitations`, request);
                        console.log(response);
                        if (!response.ok) {
                            const errorData = await response.json().catch(() => ({}));
                        }
                        const data =  await response.json();
                        if(data.success){
                            artist.remove();
                        }
                    }catch (error) {
                    }
                }
                async function resendInvite(button){
                    try {
                        let artist = button.closest('tr');
                        let id = artist.id;
                        const headers = {
                            'X-WP-Nonce': eiSettings.nonce,
                            'action_nonce': eiSettings.dash,
                            'Content-Type': 'application/json'
                        };
                        let body = {
                            user: eiSettings.currentUser,
                            refresh: id
                        };
                        let request = {
                            method: 'POST',
                            headers: headers,
                            body: JSON.stringify(body)
                        };
                        console.log(request);
                        const response = await fetch(`${eiSettings.api}invitations`, request);
                        console.log(response);
                        if (!response.ok) {
                            const errorData = await response.json().catch(() => ({}));
                        }
                        const data =  await response.json();
                    }catch (error) {
                    }
                }
                function sendInvites(button){
                    if(document.querySelector('.invited-artist')){
                        let newArtists = [];
                        document.querySelectorAll('.invited-artist').forEach(invited => {
                            let name = invited.querySelector('input[type="text"]'),
                                email = invited.querySelector('input[type="email"]'),
                                toShop = invited.querySelector('input[type="checkbox"]');
                            if(name.value === '' || email.value === ''){
                                invited.classList.add('required');
                                return;
                            }
                            newArtists.push({
                                name: name.value,
                                email: email.value,
                                toShop: toShop.checked
                            });
                            invited.remove();
                        });
                        if(newArtists.length > 0){
                            window.queueManager.addToQueue({
                                type: 'invite_artist',
                                data: newArtists
                            });
                        }
                    }
                }
            </script>
            <section class="invite-artists">
                <div class="invited-artist">
                    <button type="button" onclick="removeArtist(this)" title="Remove Invite"><?=jvbIcon('trash')?></button>
                    <div>
                        <label for="invited-artist-name-1">First Name</label>
                        <input type="text" id="invited-artist-name-1" name="invited-artist-name-1">
                    </div>
                    <div>
                        <label for="invited-artist-email-1">Email</label>
                        <input type="email" id="invited-artist-email-1" name="invited-artist-email-1">
                    </div>
                    <div>
                        <input type="checkbox" name="invited-add-to-shop-1" id="invited-add-to-shop-1">
                        <label for="invited-add-to-shop-1">Add to shop?</label>
                    </div>
                </div>
            </section>
            <div class="actions">
                <button type="button" onclick="addArtist(this)" class="add-artist"><?= jvbIcon('plus-square')?>Add Artist</button>
                <button type="button" onclick="sendInvites(this)" class="send-invites"><?=jvbIcon('envelope')?>Send Invites</button>
            </div>
            <template class="artistInvite">
                <div class="invited-artist">
                    <button type="button" onclick="removeArtist(this)" title="Remove Invite"><?=jvbIcon('trash')?></button>
                    <div>
                        <label for="invited-artist-name">First Name</label>
                        <input type="text" id="invited-artist-name" name="invited-artist-name">
                    </div>
                    <div>
                        <label for="invited-artist-email">Email</label>
                        <input type="email" id="invited-artist-email" name="invited-artist-email">
                    </div>
                    <div>
                        <input type="checkbox" name="invited-add-to-shop" id="invited-add-to-shop">
                        <label for="invited-add-to-shop">Add to shop?</label>
                    </div>
                </div>
            </template>
        </div>
        <?php
        $invites = JVB()->routes('invites')->getUserInvitations($userID);
        ?>
        <table class="artist-invite">
            <thead>
                <tr>
                    <th scope="col" style="width:100%;">Name</th>
                    <th scope="col" style="padding:0 .5rem">Email</th>
                    <th scope="col" style="padding:0 .5rem">Status</th>
                    <th scope="col" style="padding:0 .5rem">Expires</th>
                    <th scope="col" style="padding:0 .5rem">Actions</th>
                </tr>
            </thead>
            <tbody>
            <?php
            if (!empty($invites->invitations)) {
                foreach ($invites->invitations as $invite) {
                    ?>
                    <tr id="<?=$invite['id']?>">
                        <td>
                            <?=$invite['name']?>
                        </td>
                        <td>
                            <?=$invite['email']?>
                        </td>
                        <td>
                            <?=$invite['status']?>
                        </td>
                        <td>
                            <?=$invite['expires_at']?>
                        </td>
                        <td class="actions">
                            <button type="button" data-action="revoke" title="Revoke Invitation" onclick="revokeInvite(this)">
                                <?=jvbIcon('trash')?>
                                <span class="screen-reader-text">Revoke invite</span>
                            </button>
                            <button type="button" data-action="resend"<?=($invite['status'] === 'exipired') ? '' : ' disabled'?> title="Resend Invitation" onclick="resendInvite(this)">
                                <?=jvbIcon('arrows-clockwise')?>
                                <span class="screen-reader-text">Try Again</span>
                            </button>
                        </td>
                    </tr>
                    <?php
                }
            } else {
                ?>
                <tr><td><i>No invites yet</i></td><td></td><td></td><td></td><td></td></tr>
                <?php
            }
            ?>
            </tbody>
        </table>
        <?php
    }
}
//TODO: Likely replaced with Registrar?
//
//class UserSettings extends ContentRegistry
//{
//    protected array $fields;
//    protected array $sections = [
//        'account'   => [
//            'title'         => 'Account',
//            'icon'          => 'settings',
//        ],
//        'notifications' => [
//            'title'         => 'Notifications',
//            'icon'          => 'email'
//        ],
//        'newsletter' => [
//            'title'         => 'Newsletter',
//            'icon'          => 'logo'
//        ],
//        'invitations'    => [
//            'title'        => 'Invite Artists',
//            'icon'        => 'new-user',
//        ]
//    ];
//    protected array $frequency = [
//        'never'     => 'Never',
//        'daily'     => 'Daily',
//        'weekly'    => 'Weekly',
//        'monthly'   => 'Monthly',
//    ];
//
//    public function initType():void
//    {
//        $this->object_type = 'user';
//        $this->userFields();
//    }
//
//    public function getFields():array
//    {
//        return $this->fields;
//    }
//    public function getSections():array
//    {
//        return $this->sections;
//    }
//    public function userFields():void
//    {
//
//        $this->fields = [
//            'display_name'  => [
//                'type'  => 'text',
//                'label' => 'Name',
//                'description'   => 'Optional. Only used if you allow artists to see your info when you favourite them.',
//                'default'   => '',
//                'section'   => 'account',
//                'role'      => ['ei_enthusiast']
//            ],
//            'user_email'    => [
//                'type'  => 'email',
//                'label' => 'Email',
//                'description'   => 'Required for any notifications you subscribe to.',
//                'default'   => '',
//                'section'   => 'account',
//                'role'      => ['ei_enthusiast']
//            ],
//            'city'      => [
//                'type'  => 'text',
//                'label' => 'City',
//                'description'   => 'Optional. Just helps us know where people who use this site are located.',
//                'default'   => '',
//                'section'   => 'account',
//                'role'      => ['ei_enthusiast']
//            ],
//            'notify'    => [
//                'type'  => 'true_false',
//                'label' => 'Notify artists when you favourite their work',
//                'description'   => 'If you select this, artists will see your name when you favourite their work, else they will just get an anonymous notification.',
//                'default'   => false,
//                'section'   => 'account',
//            ],
//            'dark_mode'    => [
//                'type'  => 'true_false',
//                'label' => 'Dark Mode',
//                'default'   => false,
//            ],
//            'email_digest'  => [
//                'type'      => 'radio',
//                'label'     => 'Email Summary Frequency',
//                'options'   => $this->frequency,
//                'default'   => 'never',
//                'section'       => 'notifications'
//            ],
//            'digest_override'   => [
//                'type'  => 'true_false',
//                'label' => 'Apply to all notifications',
//                'description'   => 'Override individual notification settings and apply this frequency to all your notifications',
//                'default'     => false,
//                'section'       => 'notifications'
//            ],
//            'notifications' => [
//                'type'      => 'callback',
//                'callback'  => 'renderNotifications',
//                'label'     => 'Notifications',
//                'section'   => 'notifications',
//                'default'   => '',
//            ],
//            'site_updates'  => [
//                'type'  => 'true_false',
//                'label' => 'Site Updates',
//                'description' => 'Get notified when new features are added to edmonton.ink',
//                'default'   => false,
//                'section'   => 'account',
//            ],
//            'newsletter'    => [
//                'type'  => 'true_false',
//                'label' => 'Newsletter',
//                'description'   => 'Sign up for our monthly-ish newsletter, featuring upcoming events, featured artists, new artists, and their work.',
//                'default'   => false,
//                'section'   => 'newsletter',
//            ],
//            'owner_of'    => [
//                'type' => 'selector',
//          'subtype'=> 'taxonomy',
//                'label'    => __('Owner of', 'jvb'),
//                'isReference' => true,
//                'taxonomy' => BASE. 'shop',
//                'quickEdit'    => true,
//                'default'    => '',
//            ],
//            'manager_of'    => [
//                'type' => 'selector',
//                'subtype' => 'taxonomy',
//                'label'    => __('Manager of', 'jvb'),
//                'isReference' => true,
//                'taxonomy' => BASE. 'shop',
//                'hidden'    => true,
//                'default'    => '',
//            ],
//
//            'invitations'    => [
//                'type'    => 'callback',
//                'callback'    => 'handleInvitationsManagement',
//                'section'    => 'invitations',
//                'label'        => __('Invite Artists', 'jvb'),
//                'role'      => ['ei_artist']
//            ],
//        ];
//    }
//
//    /**
//     * Render custom notification preferences UI
//     * @param int $user_id
//     *
//     * @return string
//     */
//    public function renderNotifications(int $user_id):string
//    {
//        $favourites = $this->getUserFavourites($user_id);
//        $preferences = $this->getUserNotificationPreferences($user_id);
//        global $notify;
//
//        ob_start();
//        ?>
<!--        <div class="notification-preferences">-->
<!--            --><?php //foreach ($favourites as $type => $items) : ?>
<!--                <details class="notification-group">-->
<!--                    <summary class="notification-group-header row x-btw">-->
<!--                        <span class="type-label">--><?php //=jvbIcon('heart', ['style' => 'fill'])?><!-- --><?php //= $notify[$type] ?><!--</span>-->
<!--                        <span class="type-count">( --><?php //= count($items); ?><!-- )</span>-->
<!--                    </summary>-->
<!---->
<!--                    --><?php //if (!empty($items)) : ?>
<!--                        <table class="notification-table">-->
<!--                            <thead>-->
<!--                            <tr>-->
<!--                                <th>Name</th>-->
<!--                                <th>Frequency</th>-->
<!--                            </tr>-->
<!--                            </thead>-->
<!--                            <tbody>-->
<!--                            --><?php //foreach ($items as $item) : ?>
<!--                                --><?php
//                                $current = isset($preferences['preferences'][$type][$item['id']])
//                                    ? $preferences['preferences'][$type][$item['id']]
//                                    : $preferences['default_frequency'];
//                                ?>
<!--                                <tr>-->
<!--                                    <td>--><?php //= esc_html($item['name']); ?><!--</td>-->
<!--                                    <td>-->
<!--                                        <div class="radio-options row">-->
<!--                                            --><?php //foreach (['never', 'daily', 'weekly', 'monthly'] as $freq) : ?>
<!--                                                <input type="radio"-->
<!--                                                       name="notification_preferences[--><?php //= esc_attr($type); ?><!--][--><?php //= esc_attr($item['id']); ?><!--]"-->
<!--                                                       id="--><?php //= esc_attr("{$type}_{$item['id']}_$freq"); ?><!--"-->
<!--                                                       value="--><?php //= esc_attr($freq); ?><!--"-->
<!--                                                    --><?php //checked($current, $freq); ?><!-->-->
<!--                                                <label for="--><?php //= esc_attr("{$type}_{$item['id']}_$freq"); ?><!--">-->
<!--                                                    --><?php //= ucfirst($freq); ?>
<!--                                                </label>-->
<!--                                            --><?php //endforeach; ?>
<!--                                        </div>-->
<!--                                    </td>-->
<!--                                </tr>-->
<!--                            --><?php //endforeach; ?>
<!--                            </tbody>-->
<!--                            <tfoot>-->
<!--                            <tr>-->
<!---->
<!--                                <th>Set all --><?php //= $type ?><!--s to: </th>-->
<!--                                <th>-->
<!--                                    <div class="radio-options row">-->
<!--                                        --><?php //foreach (['never', 'daily', 'weekly', 'monthly'] as $freq) : ?>
<!--                                            <input type="radio"-->
<!--                                                   name="toggle-all---><?php //=$type?><!--"-->
<!--                                                   id="toggle-all---><?php //=$type?><!-----><?php //=$freq?><!--"-->
<!--                                                   value="--><?php //= esc_attr($freq); ?><!--"-->
<!--                                                class="toggle-all">-->
<!--                                            <label for="toggle-all---><?php //=$type?><!-----><?php //=$freq?><!--">-->
<!--                                                --><?php //= ucfirst($freq); ?>
<!--                                            </label>-->
<!--                                        --><?php //endforeach; ?>
<!--                                    </div>-->
<!--                                </th>-->
<!---->
<!--                            </tr>-->
<!--                            </tfoot>-->
<!--                        </table>-->
<!--                    --><?php //else : ?>
<!--                        <p class="no-items">No favourites yet</p>-->
<!--                    --><?php //endif; ?>
<!--                </details>-->
<!--            --><?php //endforeach; ?>
<!--        </div>-->
<!--        <script>-->
<!--            function initGroupOverrides() {-->
<!--                document.querySelectorAll('.toggle-all').forEach(toggle => {-->
<!--                    toggle.addEventListener('change', e => {-->
<!--                        e.preventDefault();-->
<!--                        if(toggle.checked){-->
<!--                            const table = e.target.closest('table');-->
<!--                            console.log(table);-->
<!--                            const value = toggle.value;-->
<!---->
<!--                            // Enable/disable individual controls-->
<!--                            table.querySelectorAll('input[value="'+value+'"]').forEach(radio => {-->
<!--                                radio.checked = true;-->
<!--                            });-->
<!--                        }-->
<!---->
<!--                    });-->
<!--                });-->
<!---->
<!--                // Listen for changes to default frequency-->
<!--                document.querySelector('input[name="digest_override"]').addEventListener('change', e=>{-->
<!--                    let value = document.querySelector('input[name="email_digest"]:checked').value;-->
<!---->
<!--                    console.log(value);-->
<!--                    document.querySelectorAll('input[value="'+value+'"]').forEach(toggle => {-->
<!--                        toggle.checked = true;-->
<!--                    });-->
<!---->
<!--                    setTimeout(function () {-->
<!--                        e.target.checked = false;-->
<!--                    }, 1000)-->
<!---->
<!--                });-->
<!---->
<!--            }-->
<!--            initGroupOverrides();-->
<!--        </script>-->
<!--        --><?php
//        return ob_get_clean();
//    }
//
//    /**
//     * Get user's favourites grouped by type
//     */
//    protected function getUserFavourites(int $user_id):array
//    {
//        global $wpdb;
//        $table = $wpdb->prefix . BASE.'favourites';
//        global $notify;
//        global $types;
//
//
//        $favourites = [];
//        foreach (array_keys($notify) as $type) {
//            $favourites[$type] = [];
//        }
//
//        // Fetch favourites from database
//        $results = $wpdb->get_results($wpdb->prepare(
//            "SELECT * FROM $table WHERE user_id = %d",
//            $user_id
//        ));
//
//        foreach ($results as $result) {
//            $type = str_replace(BASE, '', $result->type);
//
//
//            if (!array_key_exists($type, $favourites)) {
//                continue;
//            }
//            // Get proper name based on type
//            switch ($types[BASE.$type]['table']) {
//                case 'post':
//                    $name = get_the_title($result->target_id);
//                    break;
//                case 'term':
//                    $term = get_term($result->target_id, BASE.$type);
//                    $name = $term ? html_entity_decode($term->name) : '';
//                    break;
//                default:
//                    $name = '';
//            }
//
//            if ($name) {
//                $favourites[$type][] = [
//                    'id' => $result->target_id,
//                    'name' => $name
//                ];
//            }
//        }
//
//        return $favourites;
//    }
//
//    /**
//     * Get current notification preferences
//     */
//    protected function getNotificationPreferences(int $user_id):array
//    {
//        return get_user_meta($user_id, 'notification_preferences', true) ?: [];
//    }
//
//    protected function getUserNotificationPreferences(int $user_id):array
//    {
//        global $wpdb;
//        $table = $wpdb->prefix . BASE.'notification_preferences';
//
////        error_log('Getting notification preferences for user: ' . $user_id);
//
//        // Get user's preferences from the table
//        $raw_preferences = $wpdb->get_results($wpdb->prepare(
//            "SELECT notification_type, item_id, frequency
//         FROM {$table}
//         WHERE user_id = %d",
//            $user_id
//        ), ARRAY_A);
//
////        error_log('Raw preferences from database: ' . print_r($raw_preferences, true));
//
//        // Structure the preferences
//        $preferences = [];
//        if (!empty($raw_preferences)) {
//            foreach ($raw_preferences as $pref) {
//                $type = $pref['notification_type'];
//                $item_id = intval($pref['item_id']);
//                $frequency = $pref['frequency'];
//
//                if (!isset($preferences[$type])) {
//                    $preferences[$type] = [];
//                }
//                $preferences[$type][$item_id] = $frequency;
//            }
//        }
//
//        // Get default frequency
//        $default_frequency = get_user_meta($user_id, BASE.'email_digest', true) ?: 'never';
//
////        error_log('Structured preferences: ' . print_r($preferences, true));
////        error_log('Default frequency: ' . $default_frequency);
//
//        return [
//            'preferences' => $preferences,
//            'default_frequency' => $default_frequency
//        ];
//    }
//
//    public function handleInvitationsManagement(int $userID):void
//    {
//        $name = 'artist_invite';
//        ?>
<!--        <div class="field">-->
<!--            <script type="text/javascript">-->
<!--                function addArtist(button){-->
<!--                    let template = window.getTemplate('artistInvite');-->
<!--                    let container = button.closest('.field').querySelector('.invite-artists');-->
<!---->
<!--                    let nameLabel = template.querySelector('label[for="invited-artist-name"]'),-->
<!--                        nameInput = template.querySelector('input#invited-artist-name'),-->
<!--                        emailLabel = template.querySelector('label[for="invited-artist-email"]'),-->
<!--                        emailInput = template.querySelector('input#invited-artist-email'),-->
<!--                        shopLabel = template.querySelector('label[for="invited-add-to-shop"]'),-->
<!--                        shopInput = template.querySelector('input#invited-add-to-shop');-->
<!---->
<!---->
<!--                    let count = container.childNodes.length;-->
<!--                    console.log(container.childNodes);-->
<!--                    [-->
<!--                        nameLabel.htmlFor,-->
<!--                        nameInput.id,-->
<!--                        nameInput.name,-->
<!--                        emailLabel.htmlFor,-->
<!--                        emailInput.id,-->
<!--                        emailInput.name,-->
<!--                        shopLabel.htmlFor,-->
<!--                        shopInput.id,-->
<!--                        shopInput.name-->
<!--                    ] =-->
<!--                    [-->
<!--                        `${nameLabel.getAttribute('for')}-${count}`,-->
<!--                        `${nameInput.id}-${count}`,-->
<!--                        `${nameInput.name}-${count}`,-->
<!--                        `${emailLabel.htmlFor}-${count}`,-->
<!--                        `${emailInput.id}-${count}`,-->
<!--                        `${emailInput.name}-${count}`,-->
<!--                        `${shopLabel.htmlFor}-${count}`,-->
<!--                        `${shopInput.id}-${count}`,-->
<!--                        `${shopInput.name}-${count}`-->
<!--                    ];-->
<!--                    container.append(template);-->
<!--                }-->
<!--                function removeArtist(button){-->
<!--                    button.closest('.invited-artist').remove();-->
<!--                }-->
<!---->
<!--                async function revokeInvite(button){-->
<!--                    try {-->
<!--                        let artist = button.closest('tr');-->
<!--                        let id = artist.id;-->
<!---->
<!--                        const headers = {-->
<!--                            'X-WP-Nonce': eiSettings.nonce,-->
<!--                            'action_nonce': eiSettings.dash,-->
<!--                            'Content-Type': 'application/json'-->
<!--                        };-->
<!---->
<!--                        let body = {-->
<!--                            user: eiSettings.currentUser,-->
<!--                            revoke: id-->
<!--                        };-->
<!--                        let request = {-->
<!--                            method: 'POST',-->
<!--                            headers: headers,-->
<!--                            body: JSON.stringify(body)-->
<!--                        };-->
<!--                        console.log(request);-->
<!---->
<!---->
<!--                        const response = await fetch(`${eiSettings.api}invitations`, request);-->
<!---->
<!--                        console.log(response);-->
<!--                        if (!response.ok) {-->
<!--                            const errorData = await response.json().catch(() => ({}));-->
<!--                        }-->
<!---->
<!--                        const data =  await response.json();-->
<!--                        if(data.success){-->
<!--                            artist.remove();-->
<!--                        }-->
<!--                    }catch (error) {-->
<!--                    }-->
<!--                }-->
<!---->
<!--                async function resendInvite(button){-->
<!--                    try {-->
<!--                        let artist = button.closest('tr');-->
<!--                        let id = artist.id;-->
<!---->
<!--                        const headers = {-->
<!--                            'X-WP-Nonce': eiSettings.nonce,-->
<!--                            'action_nonce': eiSettings.dash,-->
<!--                            'Content-Type': 'application/json'-->
<!--                        };-->
<!---->
<!--                        let body = {-->
<!--                            user: eiSettings.currentUser,-->
<!--                            refresh: id-->
<!--                        };-->
<!--                        let request = {-->
<!--                            method: 'POST',-->
<!--                            headers: headers,-->
<!--                            body: JSON.stringify(body)-->
<!--                        };-->
<!--                        console.log(request);-->
<!---->
<!---->
<!--                        const response = await fetch(`${eiSettings.api}invitations`, request);-->
<!---->
<!--                        console.log(response);-->
<!--                        if (!response.ok) {-->
<!--                            const errorData = await response.json().catch(() => ({}));-->
<!--                        }-->
<!---->
<!--                        const data =  await response.json();-->
<!---->
<!--                    }catch (error) {-->
<!--                    }-->
<!--                }-->
<!---->
<!--                function sendInvites(button){-->
<!--                    if(document.querySelector('.invited-artist')){-->
<!--                        let newArtists = [];-->
<!--                        document.querySelectorAll('.invited-artist').forEach(invited => {-->
<!--                            let name = invited.querySelector('input[type="text"]'),-->
<!--                                email = invited.querySelector('input[type="email"]'),-->
<!--                                toShop = invited.querySelector('input[type="checkbox"]');-->
<!--                            if(name.value === '' || email.value === ''){-->
<!--                                invited.classList.add('required');-->
<!--                                return;-->
<!--                            }-->
<!---->
<!--                            newArtists.push({-->
<!--                                name: name.value,-->
<!--                                email: email.value,-->
<!--                                toShop: toShop.checked-->
<!--                            });-->
<!--                            invited.remove();-->
<!--                        });-->
<!--                        if(newArtists.length > 0){-->
<!--                            window.queueManager.addToQueue({-->
<!--                                type: 'invite_artist',-->
<!--                                data: newArtists-->
<!--                            });-->
<!--                        }-->
<!--                    }-->
<!--                }-->
<!--            </script>-->
<!---->
<!--            <section class="invite-artists">-->
<!--                <div class="invited-artist">-->
<!--                    <button type="button" onclick="removeArtist(this)" title="Remove Invite">--><?php //=jvbIcon('trash')?><!--</button>-->
<!--                    <div>-->
<!--                        <label for="invited-artist-name-1">First Name</label>-->
<!--                        <input type="text" id="invited-artist-name-1" name="invited-artist-name-1">-->
<!--                    </div>-->
<!--                    <div>-->
<!--                        <label for="invited-artist-email-1">Email</label>-->
<!--                        <input type="email" id="invited-artist-email-1" name="invited-artist-email-1">-->
<!--                    </div>-->
<!--                    <div>-->
<!--                        <input type="checkbox" name="invited-add-to-shop-1" id="invited-add-to-shop-1">-->
<!--                        <label for="invited-add-to-shop-1">Add to shop?</label>-->
<!--                    </div>-->
<!--                </div>-->
<!--            </section>-->
<!--            <div class="actions">-->
<!--                <button type="button" onclick="addArtist(this)" class="add-artist">--><?php //= jvbIcon('plus-square')?><!--Add Artist</button>-->
<!--                <button type="button" onclick="sendInvites(this)" class="send-invites">--><?php //=jvbIcon('envelope')?><!--Send Invites</button>-->
<!--            </div>-->
<!---->
<!--            <template class="artistInvite">-->
<!--                <div class="invited-artist">-->
<!--                    <button type="button" onclick="removeArtist(this)" title="Remove Invite">--><?php //=jvbIcon('trash')?><!--</button>-->
<!--                    <div>-->
<!--                        <label for="invited-artist-name">First Name</label>-->
<!--                        <input type="text" id="invited-artist-name" name="invited-artist-name">-->
<!--                    </div>-->
<!--                    <div>-->
<!--                        <label for="invited-artist-email">Email</label>-->
<!--                        <input type="email" id="invited-artist-email" name="invited-artist-email">-->
<!--                    </div>-->
<!--                    <div>-->
<!--                        <input type="checkbox" name="invited-add-to-shop" id="invited-add-to-shop">-->
<!--                        <label for="invited-add-to-shop">Add to shop?</label>-->
<!--                    </div>-->
<!--                </div>-->
<!--            </template>-->
<!--        </div>-->
<!--        --><?php
//
//        $invites = JVB()->routes('invites')->getUserInvitations($userID);
//
//        ?>
<!--        <table class="artist-invite">-->
<!--            <thead>-->
<!--                <tr>-->
<!--                    <th scope="col" style="width:100%;">Name</th>-->
<!--                    <th scope="col" style="padding:0 .5rem">Email</th>-->
<!--                    <th scope="col" style="padding:0 .5rem">Status</th>-->
<!--                    <th scope="col" style="padding:0 .5rem">Expires</th>-->
<!--                    <th scope="col" style="padding:0 .5rem">Actions</th>-->
<!--                </tr>-->
<!--            </thead>-->
<!--            <tbody>-->
<!--            --><?php
//            if (!empty($invites->invitations)) {
//                foreach ($invites->invitations as $invite) {
//                    ?>
<!--                    <tr id="--><?php //=$invite['id']?><!--">-->
<!--                        <td>-->
<!--                            --><?php //=$invite['name']?>
<!--                        </td>-->
<!--                        <td>-->
<!--                            --><?php //=$invite['email']?>
<!--                        </td>-->
<!--                        <td>-->
<!--                            --><?php //=$invite['status']?>
<!--                        </td>-->
<!--                        <td>-->
<!--                            --><?php //=$invite['expires_at']?>
<!--                        </td>-->
<!--                        <td class="actions">-->
<!--                            <button type="button" data-action="revoke" title="Revoke Invitation" onclick="revokeInvite(this)">-->
<!--                                --><?php //=jvbIcon('trash')?>
<!--                                <span class="screen-reader-text">Revoke invite</span>-->
<!--                            </button>-->
<!--                            <button type="button" data-action="resend"--><?php //=($invite['status'] === 'exipired') ? '' : ' disabled'?><!-- title="Resend Invitation" onclick="resendInvite(this)">-->
<!--                                --><?php //=jvbIcon('arrows-clockwise')?>
<!--                                <span class="screen-reader-text">Try Again</span>-->
<!--                            </button>-->
<!--                        </td>-->
<!---->
<!--                    </tr>-->
<!--                    --><?php
//                }
//            } else {
//                ?>
<!--                <tr><td><i>No invites yet</i></td><td></td><td></td><td></td><td></td></tr>-->
<!--                --><?php
//            }
//            ?>
<!--            </tbody>-->
<!--        </table>-->
<!--        --><?php
//    }
//}