From a9654f00c8fbc9934289d761843ddd071025013f Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 28 Aug 2026 17:20:28 +0000
Subject: [PATCH] =PHPStorm Code Inspection: fixed class reference errors (from getting rid of JVB() and replacing with direct class::getInstance; as well as general code sniffing, etc
---
inc/users/UserSettings.php | 1254 +++++++++++++++++++++++++++++-----------------------------
1 files changed, 628 insertions(+), 626 deletions(-)
diff --git a/inc/users/UserSettings.php b/inc/users/UserSettings.php
index 2fa3097..a7c8c95 100644
--- a/inc/users/UserSettings.php
+++ b/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 ? $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('delete')?></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('add')?>Add Artist</button>
- <button type="button" onclick="sendInvites(this)" class="send-invites"><?=jvbIcon('email')?>Send Invites</button>
- </div>
-
- <template class="artistInvite">
- <div class="invited-artist">
- <button type="button" onclick="removeArtist(this)" title="Remove Invite"><?=jvbIcon('delete')?></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('delete')?>
- <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('refresh')?>
- <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
+// }
+//}
--
Gitblit v1.10.0