Jake Vanderwerf
2026-01-02 b5abd615697146beeca6dba4acd057d049554a30
inc/managers/ReferralManager.php
@@ -142,11 +142,17 @@
      ];
      if (Features::hasIntegration('cloudflare') && JVB()->connect('cloudflare')->isSetUp()) {
         $requirements[] = 'cloudflare-turnstile';
         JVB()->connect('cloudflare')->enqueueTurnstileScripts();
      }
      if (is_singular(BASE.'dash')) {
         $requirements[] = 'jvb-form';
         $requirements[] = 'jvb-view';
         wp_enqueue_script('jvb-referral-admin',
         JVB_URL.'assets/js/min/referralAdmin.min.js',
         ['jvb-referral'],
         '1.0.0',
         true);
      }
      wp_enqueue_script(
         'jvb-referral',
@@ -653,11 +659,8 @@
   {
      $yesterday = date('Y-m-d', strtotime('-1 day'));
      // Get new referrals from yesterday
      $new_referrals = $this->wpdb->get_results($this->wpdb->prepare(
         "SELECT
            r.*,
            u.display_name as referrer_name
         "SELECT r.*, u.display_name as referrer_name
        FROM {$this->referrals_table} r
        JOIN {$this->wpdb->users} u ON r.referrer_id = u.ID
        WHERE DATE(r.referred_at) = %s
@@ -665,48 +668,46 @@
         $yesterday
      ));
      // Only send if there's at least 1 new referral
      if (empty($new_referrals)) {
         return;
      }
      // Build email content
      $content = '<h2>Daily Referral Report</h2>';
      $content .= '<p><strong>' . count($new_referrals) . '</strong> new referral' .
         (count($new_referrals) !== 1 ? 's' : '') . ' yesterday (' . $yesterday . ')</p>';
      $content = JVB()->email()->h1('Daily Referral Report');
      $content .= JVB()->email()->stat(
         count($new_referrals),
         count($new_referrals) === 1 ? 'New Referral' : 'New Referrals',
         'From ' . $yesterday
      );
      $content .= '<table style="width:100%; border-collapse: collapse; margin: 20px 0;">';
      $content .= '<thead><tr style="background: #f5f5f5;">';
      $content .= '<th style="padding: 10px; text-align: left; border: 1px solid #ddd;">Referee</th>';
      $content .= '<th style="padding: 10px; text-align: left; border: 1px solid #ddd;">Email</th>';
      $content .= '<th style="padding: 10px; text-align: left; border: 1px solid #ddd;">Referrer</th>';
      $content .= '<th style="padding: 10px; text-align: left; border: 1px solid #ddd;">Code</th>';
      $content .= '</tr></thead><tbody>';
      $content .= JVB()->email()->spacer(20);
      $content .= JVB()->email()->h2('New Referrals');
      // Build list of referrals
      foreach ($new_referrals as $ref) {
         $content .= '<tr>';
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($ref->referee_name));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($ref->referee_email));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($ref->referrer_name));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($ref->referral_code));
         $content .= '</tr>';
         $cardContent = sprintf(
            '<p><strong>%s</strong> (%s)</p>',
            esc_html($ref->referee_name),
            esc_html($ref->referee_email)
         );
         $cardContent .= sprintf(
            '<p style="font-size:13px;color:%s;">Referred by: %s | Code: %s</p>',
            JVB()->email()->colours['dark-200'],
            esc_html($ref->referrer_name),
            JVB()->email()->badge($ref->referral_code, 'info')
         );
         $content .= JVB()->email()->card($cardContent);
      }
      $content .= '</tbody></table>';
      // Get admin email
      $to = get_option('admin_email');
      $subject = sprintf('[%s] %d New Referral%s',
      $subject = sprintf(
         '[%s] %d New Referral%s',
         get_bloginfo('name'),
         count($new_referrals),
         count($new_referrals) !== 1 ? 's' : '');
         count($new_referrals) !== 1 ? 's' : ''
      );
      JVB()->email()->sendEmail($to, $subject, $content);
      JVB()->email()->sendEmail($to, $subject, $content, 'DAILY REPORT');
   }
   /**
@@ -717,19 +718,50 @@
      $top_referrers = $this->getTopReferrers(10, 'week');
      $total_referrals = $this->wpdb->get_var(
         "SELECT COUNT(*) FROM {$this->referrals_table}
             WHERE referred_at >= DATE_SUB(NOW(), INTERVAL 1 WEEK)"
         WHERE referred_at >= DATE_SUB(NOW(), INTERVAL 1 WEEK)"
      );
      if ($total_referrals == 0) {
         return;
      }
      $content = JVB()->email()->h1('Weekly Referral Summary');
      $content .= JVB()->email()->stat(
         $total_referrals,
         'Total Referrals',
         'This week'
      );
      $content .= JVB()->email()->spacer(30);
      $content .= JVB()->email()->h2('Top 10 Referrers');
      // Leaderboard style
      $rank = 1;
      foreach ($top_referrers as $referrer) {
         $rankBadge = $rank <= 3
            ? JVB()->email()->badge('#' . $rank, $rank === 1 ? 'success' : 'info')
            : '<span style="font-weight:600;color:' . JVB()->email()->colours['dark-200'] . ';">#' . $rank . '</span>';
         $cardContent = sprintf(
            '<p>%s <strong>%s</strong></p>',
            $rankBadge,
            esc_html($referrer->user_name)
         );
         $stats = [
            JVB()->email()->stat($referrer->referral_count, 'Total Referrals'),
            JVB()->email()->stat($referrer->treated_count, 'Treated')
         ];
         $cardContent .= JVB()->email()->grid($stats, 2);
         $content .= JVB()->email()->card($cardContent);
         $rank++;
      }
      $to = get_option('admin_email');
      $subject = '[' . get_bloginfo('name') . '] Weekly Referral Summary - ' . date('F j, Y');
      $message = $this->generateWeeklyReportEmail($top_referrers, $total_referrals);
      JVB()->email()->sendEmail($to, $subject, $message);
      JVB()->email()->sendEmail($to, $subject, $content, 'WEEKLY SUMMARY');
   }
   /**
@@ -760,52 +792,6 @@
   }
   /**
    * Generate HTML email for daily report
    *
    * @param array $referrals
    * @param string $period
    * @return string
    */
   protected function generateReportEmail(array $referrals, string $period): string
   {
      $count = count($referrals);
      $content = sprintf('<p>You have <strong>%d new referral%s</strong> today.</p>',
         $count,
         $count !== 1 ? 's' : ''
      );
      $content .= '<table style="width:100%; border-collapse: collapse; margin: 20px 0;">';
      $content .= '<thead><tr style="background: #f5f5f5; text-align: left;">';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Referred By</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">New User</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Email</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Status</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Time</th>';
      $content .= '</tr></thead><tbody>';
      foreach ($referrals as $referral) {
         $content .= '<tr>';
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($referral->referrer_name ?? 'Unknown'));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($referral->referee_name));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($referral->referee_email));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html(ucfirst($referral->status)));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html(date('g:i A', strtotime($referral->referred_at))));
         $content .= '</tr>';
      }
      $content .= '</tbody></table>';
      $content .= '<p><small>See attached CSV for full details.</small></p>';
      return jvbGetEmailTemplate($content, 'Daily Referral Report');
   }
   /**
    * Generate HTML email for weekly report
    *
    * @param array $top_referrers
@@ -820,31 +806,22 @@
         $total_referrals !== 1 ? 's' : ''
      );
      $content .= '<h3>Top 10 Referrers This Week</h3>';
      $content .= '<table style="width:100%; border-collapse: collapse; margin: 20px 0;">';
      $content .= '<thead><tr style="background: #f5f5f5; text-align: left;">';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Rank</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">User</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Total Referrals</th>';
      $content .= '<th style="padding: 10px; border: 1px solid #ddd;">Treated</th>';
      $content .= '</tr></thead><tbody>';
      $referrers = [];
      $rank = 1;
      foreach ($top_referrers as $referrer) {
         $content .= '<tr>';
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%d</td>', $rank++);
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%s</td>',
            esc_html($referrer->user_name));
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%d</td>',
            $referrer->referral_count);
         $content .= sprintf('<td style="padding: 10px; border: 1px solid #ddd;">%d</td>',
            $referrer->treated_count);
         $content .= '</tr>';
         $referrers[] = [
            'label' => '#' . $rank++ . ' - ' . esc_html($referrer->user_name),
            'value' => sprintf(
               '<strong>Total Referrals:</strong> %d | <strong>Treated:</strong> %d',
               $referrer->referral_count,
               $referrer->treated_count
            )
         ];
      }
      $content .= '</tbody></table>';
      $content .= JVB()->email()->table($referrers, 'Top 10 Referrers This Week');
      return jvbGetEmailTemplate($content, 'Weekly Referral Summary');
      return $content;
   }
   /**
@@ -1102,6 +1079,7 @@
            'autocomplete'=>'off',
            'data-referrer' => $referrer_name
         ]).'
            '.$turnstile.'
            <button type="button" class="button-secondary check-code-btn">
               '.jvbIcon('check-circle', ['size' => 16]).' Verify Code
            </button>
@@ -1113,7 +1091,6 @@
            <p class="helper-text">
               We\'ll send you a link to complete your registration.
            </p>
            '.$turnstile.'
         </form>
         <div class="success-content" hidden>
            <h3>Check Your Email!</h3>
@@ -1232,8 +1209,9 @@
         <h4>Your Referral Link</h4>
         <div class="copy-group row btw nowrap">
            <code id="referral-link" class="copy-target"><?= esc_url($share_url) ?></code>
            <button type="button" class="copy-btn" data-target="referral-link" aria-label="Copy referral link">
               <?php echo jvbIcon('copy', ['size' => 16]); ?>
            <button type="button" class="copy-btn" data-target="referral-link" title="Copy referral link">
               <?= jvbIcon('copy'); ?>
               <?= jvbIcon('check-circle'); ?>
            </button>
         </div>
         <p class="hint">Quickest and easiest: autofills your code.</p>
@@ -1242,8 +1220,9 @@
         <h4>Your Code</h4>
         <div class="copy-group row btw nowrap">
            <code id="referral-code" class="copy-target"><?= esc_html($referral_code) ?></code>
            <button type="button" class="copy-btn" data-target="referral-code" aria-label="Copy referral code">
               <?php echo jvbIcon('copy', ['size' => 16]); ?>
            <button type="button" class="copy-btn" data-target="referral-code" title="Copy referral code">
               <?= jvbIcon('copy'); ?>
               <?= jvbIcon('check-circle'); ?>
            </button>
         </div>
         <p class="hint">Manually copy and paste the code</p>
@@ -2476,20 +2455,20 @@
      <!-- Referral Code Card -->
      <div class="card">
         <h3>Share Code</h3>
         <div class="row btw nowrap">
            <code class="code"><?= esc_html($referral_code) ?></code>
            <button class="button copy-btn" data-code="<?= esc_attr($referral_code) ?>">
               Copy Code
            </button>
         </div>
         <h3>Share Link</h3>
         <div class="row btw nowrap">
            <code class="share-link">
               <?= home_url('/?ref=' . $referral_code) ?>
            </code>
            <button class="button copy-btn" data-code="<?= home_url('/?ref=' . $referral_code) ?>">
               Copy Link
            <code id="referral-link" class="copy-target"><?= home_url('/?ref=' . $referral_code) ?></code>
            <button type="button" class="copy-btn" data-target="referral-link" title="Copy referral link">
               <?= jvbIcon('copy'); ?>
               <?= jvbIcon('check-circle'); ?>
            </button>
         </div>
         <h3>Share Code</h3>
         <div class="row btw nowrap">
            <code id="referral-code" class="copy-target"><?= esc_html($referral_code) ?></code>
            <button type="button" class="copy-btn" data-target="referral-code" title="Copy referral code">
               <?= jvbIcon('copy'); ?>
               <?= jvbIcon('check-circle'); ?>
            </button>
         </div>
      </div>
@@ -2812,7 +2791,7 @@
      $referrer_first_name = $referrer ? strtok($referrer->display_name, ' ') : 'Your friend';
      // Get reward text
      $reward_text = $this->getRewardText(false); // Just "20% off" or "$25 off"
      $reward_text = $this->getRewardText(); // Just "20% off" or "$25 off"
      $booking_url = apply_filters('jvb_referral_booking_url', home_url('/contact'));
      $estimate_url = apply_filters('jvb_referral_estimate_url', home_url('/estimate'));