From e9967fa22781d922ba4eb8fb44fe72d200ac4b14 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 10 Nov 2025 21:04:10 +0000
Subject: [PATCH] =IconsManager.php update
---
inc/rest/routes/ReferralRoutes.php | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 362 insertions(+), 21 deletions(-)
diff --git a/inc/rest/routes/ReferralRoutes.php b/inc/rest/routes/ReferralRoutes.php
index d7f097f..15f293e 100644
--- a/inc/rest/routes/ReferralRoutes.php
+++ b/inc/rest/routes/ReferralRoutes.php
@@ -1,6 +1,7 @@
<?php
namespace JVBase\rest\routes;
+use JVBase\managers\ReferralManager;
use JVBase\rest\RestRouteManager;
use WP_REST_Request;
use WP_REST_Response;
@@ -15,7 +16,7 @@
*/
class ReferralRoutes extends RestRouteManager
{
-
+ protected ReferralManager $manager;
public function __construct()
{
$this->route = 'referrals';
@@ -31,6 +32,49 @@
'permission_callback' => [$this, 'checkPermission']
]);
+ register_rest_route($this->namespace, "/{$this->route}/register", [
+ 'methods' => 'POST',
+ 'callback' => [$this, 'registerWithReferral'],
+ 'permission_callback' => [$this, 'checkRateLimit'],
+ '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' => [$this, 'checkRateLimit'],
+ '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,27 +82,11 @@
'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',
'callback' => [$this, 'trackReferralClick'],
- 'permission_callback' => '__return_true',
+ 'permission_callback' => [$this, 'checkRateLimit'],
'args' => [
'code' => [
'required' => true,
@@ -84,13 +112,78 @@
]
]);
- // 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',
@@ -127,6 +220,21 @@
}
]
]);
+
+ register_rest_route($this->namespace, "/{$this->route}/add-code", [
+ 'methods' => 'POST',
+ 'callback' => [$this, 'addReferralCodeAfterRegistration'],
+ 'permission_callback' => [$this, 'checkRateLimit'],
+ 'args' => [
+ 'code' => [
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => function ($code) {
+ return strtoupper(sanitize_text_field($code));
+ }
+ ]
+ ]
+ ]);
}
public function checkPermission(WP_REST_Request $request): bool
@@ -310,4 +418,237 @@
'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);
+ }
+ if (is_user_logged_in() && get_current_user_id() === $referrer->ID) {
+ return $this->error('You cannot use your own referral code', 'self_referral', 400);
+ }
+
+ // Return basic referrer info (no sensitive data)
+ return new WP_REST_Response([
+ 'success' => true,
+ 'code' => $code,
+ 'referrer_name' => $referrer->display_name,
+ ], 200);
+ }
+
+ public function addReferralCodePostRegistration(WP_REST_Request $request): WP_REST_Response
+ {
+ if (!$this->manager) {
+ $this->manager = JVB()->referrals();
+ }
+ $user_id = get_current_user_id();
+ $code = $request->get_param('code');
+
+ // Check if user already has a referral (can't change)
+ $existing = $this->manager->getReferralByReferee($user_id);
+ if ($existing) {
+ return $this->error('You already have a referral code applied', 'already_referred', 400);
+ }
+
+ // Validate the code exists
+ $referrer = $this->manager->getUserByReferralCode($code);
+ if (!$referrer) {
+ return $this->error('Invalid referral code', 'invalid_code', 400);
+ }
+
+ // Create the referral
+ $user = wp_get_current_user();
+ $result = $this->manager->createReferral($referrer->ID, $user_id, $code);
+
+ if ($result) {
+ return $this->success([
+ 'message' => 'Referral code applied successfully!',
+ 'referrer_name' => $referrer->display_name
+ ]);
+ }
+
+ return $this->error('Failed to apply referral code', 'creation_failed', 500);
+ }
}
--
Gitblit v1.10.0