From e729f920139f0c65902be2d6b2c32466b08375e8 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 20 Oct 2025 17:54:52 +0000
Subject: [PATCH] =Form updates

---
 inc/rest/routes/ReferralRoutes.php |  342 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 313 insertions(+), 29 deletions(-)

diff --git a/inc/rest/routes/ReferralRoutes.php b/inc/rest/routes/ReferralRoutes.php
index a447a16..1589135 100644
--- a/inc/rest/routes/ReferralRoutes.php
+++ b/inc/rest/routes/ReferralRoutes.php
@@ -1,10 +1,10 @@
 <?php
-namespace JVBase\rest;
+namespace JVBase\rest\routes;
 
+use JVBase\rest\RestRouteManager;
 use WP_REST_Request;
 use WP_REST_Response;
 use WP_Error;
-use JVBase\managers\ReferralManager;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -15,12 +15,10 @@
  */
 class ReferralRoutes extends RestRouteManager
 {
-	protected ReferralManager $manager;
 
 	public function __construct()
 	{
 		$this->route = 'referrals';
-		$this->manager = new ReferralManager();
 		parent::__construct();
 	}
 
@@ -33,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',
@@ -40,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',
@@ -86,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',
@@ -149,7 +237,7 @@
 			'offset' => $request->get_param('offset') ?? 0
 		];
 
-		$referrals = $this->manager->getUserReferrals($user_id, $args);
+		$referrals = JVB()->referrals()->getUserReferrals($user_id, $args);
 
 		return new WP_REST_Response([
 			'success' => true,
@@ -163,7 +251,7 @@
 	public function getReferralCode(WP_REST_Request $request): WP_REST_Response
 	{
 		$user_id = get_current_user_id();
-		$code = $this->manager->getUserReferralCode($user_id);
+		$code = JVB()->referrals()->getUserReferralCode($user_id);
 
 		if (is_wp_error($code)) {
 			return new WP_REST_Response([
@@ -187,7 +275,7 @@
 		$user_id = get_current_user_id();
 		$new_code = strtoupper(sanitize_text_field($request->get_param('code')));
 
-		$result = $this->manager->getUserReferralCode($user_id, $new_code);
+		$result = JVB()->referrals()->getUserReferralCode($user_id, $new_code);
 
 		if (is_wp_error($result)) {
 			return new WP_REST_Response([
@@ -232,7 +320,7 @@
 	{
 		$referral_id = intval($request->get_param('id'));
 
-		$result = $this->manager->markAsTreated($referral_id, true);
+		$result = JVB()->referrals()->markAsTreated($referral_id, true);
 
 		if (!$result) {
 			return new WP_REST_Response([
@@ -253,7 +341,7 @@
 	public function getUserStats(WP_REST_Request $request): WP_REST_Response
 	{
 		$user_id = get_current_user_id();
-		$stats = $this->manager->getUserStats($user_id);
+		$stats = JVB()->referrals()->getUserStats($user_id);
 
 		return new WP_REST_Response([
 			'success' => true,
@@ -269,7 +357,7 @@
 		$period = $request->get_param('period') ?? 'week';
 		$limit = $request->get_param('limit') ?? 10;
 
-		$top_referrers = $this->manager->getTopReferrers($limit, $period);
+		$top_referrers = JVB()->referrals()->getTopReferrers($limit, $period);
 
 		return new WP_REST_Response([
 			'success' => true,
@@ -312,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);
+	}
 }

--
Gitblit v1.10.0