Jake Vanderwerf
2025-10-18 b0194e10a87e16797a568d8a30d53ebecd27d8a4
inc/rest/routes/ReferralRoutes.php
@@ -31,6 +31,49 @@
         'permission_callback' => [$this, 'checkPermission']
      ]);
      register_rest_route($this->namespace, '/referrals/register', [
         'methods' => 'POST',
         'callback' => [$this, 'registerWithReferral'],
         'permission_callback' => '__return_true',
         'args' => [
            'name' => [
               'required' => true,
               'type' => 'string',
               'sanitize_callback' => 'sanitize_text_field'
            ],
            'email' => [
               'required' => true,
               'type' => 'string',
               'format' => 'email',
               'validate_callback' => function($param) {
                  return is_email($param);
               }
            ],
            'code' => [
               'required' => true,
               'type' => 'string',
               'sanitize_callback' => function($code) {
                  return strtoupper(sanitize_text_field($code));
               }
            ]
         ]
      ]);
      register_rest_route($this->namespace, '/referrals/check-code', [
         'methods' => 'POST',
         'callback' => [$this, 'checkReferralCode'],
         'permission_callback' => '__return_true',
         'args' => [
            'code' => [
               'required' => true,
               'type' => 'string',
               'sanitize_callback' => function($code) {
                  return strtoupper(sanitize_text_field($code));
               }
            ]
         ]
      ]);
      // Get or create referral code
      register_rest_route($this->namespace, "/{$this->route}/code", [
         'methods' => 'GET',
@@ -38,22 +81,6 @@
         'permission_callback' => [$this, 'checkPermission']
      ]);
      // Update referral code
      register_rest_route($this->namespace, "/{$this->route}/code", [
         'methods' => 'POST',
         'callback' => [$this, 'updateReferralCode'],
         'permission_callback' => [$this, 'checkPermission'],
         'args' => [
            'code' => [
               'required' => true,
               'type' => 'string',
               'validate_callback' => function($param) {
                  return preg_match('/^[A-Z0-9]+$/i', $param);
               }
            ]
         ]
      ]);
      // Track referral click (public endpoint)
      register_rest_route($this->namespace, "/{$this->route}/track", [
         'methods' => 'POST',
@@ -84,13 +111,76 @@
         ]
      ]);
      // Get user stats
      register_rest_route($this->namespace, "/{$this->route}/stats", [
      // Send referral invitation
      register_rest_route($this->namespace, '/'.$this->route.'/invite', [
         'methods' => 'POST',
         'callback' => [$this, 'sendInvitation'],
         'permission_callback' => [$this, 'checkPermission'],
         'args' => [
            'email' => [
               'required' => true,
               'type' => 'string',
               'format' => 'email',
               'validate_callback' => function($param) {
                  return is_email($param);
               }
            ],
            'name' => [
               'required' => true,
               'type' => 'string',
               'sanitize_callback' => 'sanitize_text_field'
            ]
         ]
      ]);
      // Send batch invitations
      register_rest_route($this->namespace, '/'.$this->route.'/invite/batch', [
         'methods' => 'POST',
         'callback' => [$this, 'sendBatchInvitations'],
         'permission_callback' => [$this, 'checkPermission'],
         'args' => [
            'invitations' => [
               'required' => true,
               'type' => 'array',
               'validate_callback' => function($param) {
                  return is_array($param) && !empty($param);
               }
            ]
         ]
      ]);
      // Get invitation stats for current user
      register_rest_route($this->namespace, '/'.$this->route.'/invite/stats', [
         'methods' => 'GET',
         'callback' => [$this, 'getUserStats'],
         'callback' => [$this, 'getInvitationStats'],
         'permission_callback' => [$this, 'checkPermission']
      ]);
      // Export referrals for Jane App
      register_rest_route($this->namespace, '/'.$this->route.'/export', [
         'methods' => 'POST',
         'callback' => [$this, 'exportReferrals'],
         'permission_callback' => function() {
            return current_user_can('manage_options');
         },
         'args' => [
            'start_date' => [
               'required' => true,
               'type' => 'string',
               'validate_callback' => function($param) {
                  return (bool) strtotime($param);
               }
            ],
            'end_date' => [
               'required' => true,
               'type' => 'string',
               'validate_callback' => function($param) {
                  return (bool) strtotime($param);
               }
            ]
         ]
      ]);
      // Get top referrers (admin only)
      register_rest_route($this->namespace, "/{$this->route}/leaderboard", [
         'methods' => 'GET',
@@ -310,4 +400,200 @@
         'settings' => $settings
      ]);
   }
   /**
    * Send a single referral invitation
    *
    * @param WP_REST_Request $request
    * @return WP_REST_Response
    */
   public function sendInvitation(WP_REST_Request $request): WP_REST_Response
   {
      $user_id = get_current_user_id();
      $email = sanitize_email($request->get_param('email'));
      $name = sanitize_text_field($request->get_param('name'));
      // Send invitation via ReferralManager
      $referral_manager = JVB()->referrals();
      $result = $referral_manager->sendReferralInvitation($user_id, $email, $name);
      if (is_wp_error($result)) {
         return new WP_REST_Response([
            'success' => false,
            'message' => $result->get_error_message(),
            'code' => $result->get_error_code()
         ], 400);
      }
      return new WP_REST_Response($result, 200);
   }
   /**
    * Send batch referral invitations
    *
    * @param WP_REST_Request $request
    * @return WP_REST_Response
    */
   public function sendBatchInvitations(WP_REST_Request $request): WP_REST_Response
   {
      $user_id = get_current_user_id();
      $invitations = $request->get_param('invitations');
      // Validate invitation format
      foreach ($invitations as $invite) {
         if (empty($invite['email']) || empty($invite['name'])) {
            return new WP_REST_Response([
               'success' => false,
               'message' => 'Each invitation must have email and name'
            ], 400);
         }
      }
      // Send batch via ReferralManager
      $referral_manager = JVB()->referrals();
      $result = $referral_manager->sendBatchReferralInvitations($user_id, $invitations);
      return new WP_REST_Response($result, 200);
   }
   /**
    * Get invitation stats for current user
    *
    * @param WP_REST_Request $request
    * @return WP_REST_Response
    */
   public function getInvitationStats(WP_REST_Request $request): WP_REST_Response
   {
      $user_id = get_current_user_id();
      $referral_manager = JVB()->referrals();
      $stats = $referral_manager->getUserInvitationStats($user_id);
      return new WP_REST_Response([
         'success' => true,
         'stats' => $stats
      ], 200);
   }
   /**
    * Export referrals for Jane App cross-reference
    * Admin only
    *
    * @param WP_REST_Request $request
    * @return WP_REST_Response
    */
   public function exportReferrals(WP_REST_Request $request): WP_REST_Response
   {
      $start_date = sanitize_text_field($request->get_param('start_date'));
      $end_date = sanitize_text_field($request->get_param('end_date'));
      $referral_manager = JVB()->referrals();
      $csv_content = $referral_manager->exportReferrals($start_date, $end_date);
      // Return CSV for download
      return new WP_REST_Response([
         'success' => true,
         'csv' => $csv_content,
         'filename' => sprintf('referrals_%s_to_%s.csv', $start_date, $end_date)
      ], 200);
   }
   public function registerWithReferral(WP_REST_Request $request): WP_REST_Response
   {
      $name = sanitize_text_field($request->get_param('name'));
      $email = sanitize_email($request->get_param('email'));
      $code = strtoupper(sanitize_text_field($request->get_param('code')));
      // Validate email
      if (!is_email($email)) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Invalid email address'
         ], 400);
      }
      // Check if user exists
      if (email_exists($email)) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'An account with this email already exists'
         ], 400);
      }
      // Validate referral code
      $referral_manager = JVB()->referrals();
      $referrer = $referral_manager->getUserByReferralCode($code);
      if (!$referrer) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Invalid referral code'
         ], 404);
      }
      // Get reward text
      $settings = $referral_manager->getRewardSettings();
      $reward_amount = $settings['referee_reward_amount'] ?? 20;
      $reward_type = $settings['referee_reward_type'] ?? 'percentage';
      $reward_text = $reward_type === 'percentage'
         ? "{$reward_amount}% off your first treatment!"
         : "\${$reward_amount} off your first treatment!";
      // Send magic link with referral context via MagicLinkManager
      $magic_link_manager = new \JVBase\managers\MagicLinkManager();
      $result = $magic_link_manager->sendMagicLink(
         $email,
         \JVBase\managers\MagicLinkManager::TYPE_REFERRAL,
         [
            'name' => $name,
            'referral_code' => $code,
            'referrer_id' => $referrer->ID,
            'referrer_name' => $referrer->display_name,
            'reward_text' => $reward_text
         ]
      );
      if (is_wp_error($result)) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Failed to send registration link. Please try again.'
         ], 500);
      }
      return new WP_REST_Response([
         'success' => true,
         'message' => 'Check your email! We sent you a link to complete your registration.',
         'email' => $email
      ], 200);
   }
   public function checkReferralCode(WP_REST_Request $request): WP_REST_Response
   {
      $code = strtoupper(sanitize_text_field($request->get_param('code')));
      if (empty($code)) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Code is required'
         ], 400);
      }
      $referral_manager = JVB()->referrals();
      $referrer = $referral_manager->getUserByReferralCode($code);
      if (!$referrer) {
         return new WP_REST_Response([
            'success' => false,
            'message' => 'Invalid referral code'
         ], 404);
      }
      // Return basic referrer info (no sensitive data)
      return new WP_REST_Response([
         'success' => true,
         'code' => $code,
         'referrer_name' => $referrer->display_name,
      ], 200);
   }
}