From 31f78d7d2ceb77688c414c1d44ae3b6c2a7f5ff1 Mon Sep 17 00:00:00 2001 From: belwalshubham Date: Tue, 8 Jul 2025 15:25:14 +0530 Subject: [PATCH 1/3] prefill details --- .../Goonjcustom/AfformFieldPrefillService.php | 82 +++++++++++++++++++ .../Civi/DroppingCenterService.php | 53 ++++++++---- 2 files changed, 118 insertions(+), 17 deletions(-) create mode 100644 wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php diff --git a/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php new file mode 100644 index 000000000..e954971e8 --- /dev/null +++ b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php @@ -0,0 +1,82 @@ +debug('[AfformPrefill] Preprocess started.'); + + $request = \CRM_Utils_Request::retrieve('token', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); + + if (!$request) { + Civi::log()->warning('[AfformPrefill] No token found in URL.'); + return; + } + + // Decrypt token + try { + $decrypted = CRM_Utils_Crypt::decrypt($request); + $data = json_decode($decrypted, true); + Civi::log()->debug('[AfformPrefill] Token decrypted: ' . print_r($data, true)); + } catch (\Exception $e) { + Civi::log()->error('[AfformPrefill] Token decryption failed: ' . $e->getMessage()); + return; + } + + if (!is_array($data)) { + Civi::log()->error('[AfformPrefill] Decrypted token is not valid JSON.'); + return; + } + + $changeSet = \Civi\Angular\ChangeSet::create('injectPrefillValues') + ->alterHtml(';\\.aff\\.html$;', function($doc, $path) use ($data) { + Civi::log()->debug("[AfformPrefill] Altering HTML template: {$path}"); + + foreach (pq('af-field', $doc) as $afField) { + $fieldName = $afField->getAttribute('name'); + + if (!$fieldName) { + continue; + } + + if (array_key_exists($fieldName, $data)) { + $fieldDefn = self::getFieldDefinition($afField); + + if (!$fieldDefn) { + Civi::log()->warning("[AfformPrefill] No field definition for: {$fieldName}"); + continue; + } + + // Inject default value and make read-only + $fieldDefn['afform_default'] = $data[$fieldName]; + $fieldDefn['readonly'] = true; + + pq($afField)->attr('defn', htmlspecialchars(\CRM_Utils_JS::writeObject($fieldDefn), ENT_COMPAT)); + Civi::log()->info("[AfformPrefill] Prefilled field '{$fieldName}' with value: " . json_encode($data[$fieldName])); + } else { + Civi::log()->debug("[AfformPrefill] Field '{$fieldName}' not in token data, skipping."); + } + } + }); + + $event->angular->add($changeSet); + Civi::log()->debug('[AfformPrefill] ChangeSet injected successfully.'); + } + + public static function getFieldDefinition($afField) { + $existingFieldDefn = trim(pq($afField)->attr('defn') ?: ''); + + if ($existingFieldDefn && $existingFieldDefn[0] !== '{') { + return NULL; + } + + return $existingFieldDefn ? \CRM_Utils_JS::getRawProps($existingFieldDefn) : []; + } +} \ No newline at end of file diff --git a/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php b/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php index d5eee758f..75ef7235e 100644 --- a/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php +++ b/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php @@ -543,12 +543,29 @@ public static function processDispatchEmail(string $op, string $objectName, $obj * */ public static function sendDispatchEmail($email, $initiatorName, $droppingCenterId, $contactId, $goonjOffice, $goonjOfficeName) { - $homeUrl = \CRM_Utils_System::baseCMSURL(); - $vehicleDispatchFormUrl = $homeUrl . '/vehicle-dispatch/#?Camp_Vehicle_Dispatch.Dropping_Center=' . $droppingCenterId . '&Camp_Vehicle_Dispatch.Filled_by=' . $contactId . '&Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent=' . $goonjOffice . '&Camp_Vehicle_Dispatch.Goonj_Office_Name=' . $goonjOfficeName . '&Eck_Collection_Camp1=' . $droppingCenterId; + $homeUrl = \CRM_Utils_System::baseCMSURL(); + + // Step 1: Gather data + $dispatchData = [ + 'Camp_Vehicle_Dispatch.Dropping_Center' => $droppingCenterId, + 'Camp_Vehicle_Dispatch.Filled_by' => $contactId, + 'Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent' => $goonjOffice, + 'Camp_Vehicle_Dispatch.Goonj_Office_Name' => $goonjOfficeName, + 'Eck_Collection_Camp1' => $droppingCenterId, + 'id' => $droppingCenterId, + ]; + + // Step 2: Convert to JSON and encrypt + $json = json_encode($dispatchData); + $token = \CRM_Utils_Crypt::encrypt($json); - $emailHtml = " - - + // Step 3: Generate encrypted URL + $vehicleDispatchFormUrl = $homeUrl . '/vehicle-dispatch/?token=' . urlencode($token); + + // Step 4: Compose HTML email + $emailHtml = " + +

Dear {$initiatorName},

Thank you so much for your invaluable efforts in running the Goonj Dropping Center. Your dedication plays a crucial role in our work, and we deeply appreciate your continued support.

@@ -556,19 +573,21 @@ public static function sendDispatchEmail($email, $initiatorName, $droppingCenter This will help us to verify and acknowledge the materials as soon as they arrive.

We truly appreciate your cooperation and continued commitment to our cause.

Warm Regards,
Team Goonj..

- - - "; - $from = HelperService::getDefaultFromEmail(); - $mailParams = [ - 'subject' => 'Kindly fill the Dispatch Form for Material Pickup', - 'from' => $from, - 'toEmail' => $email, - 'html' => $emailHtml, - ]; + + + "; + + // Step 5: Send email + $from = HelperService::getDefaultFromEmail(); + $mailParams = [ + 'subject' => 'Kindly fill the Dispatch Form for Material Pickup', + 'from' => $from, + 'toEmail' => $email, + 'html' => $emailHtml, + ]; - \CRM_Utils_Mail::send($mailParams); - } + \CRM_Utils_Mail::send($mailParams); +} /** * From a5e5eb8d0c693e5ada963df15fea4399ec7ee737 Mon Sep 17 00:00:00 2001 From: belwalshubham Date: Wed, 16 Jul 2025 14:44:14 +0530 Subject: [PATCH 2/3] call prefill field --- .../Goonjcustom/AfformFieldPrefillService.php | 90 +++++++++---------- .../goonjcustom/goonjcustom.php | 7 ++ 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php index e954971e8..499721131 100644 --- a/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php +++ b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/AfformFieldPrefillService.php @@ -10,65 +10,63 @@ */ class CRM_Goonjcustom_AfformFieldPrefillService extends AutoService { - public static function preprocess(GenericHookEvent $event) { - Civi::log()->debug('[AfformPrefill] Preprocess started.'); + public static function preprocess(\Civi\Angular\Manager $angular) { + Civi::log()->debug('[AfformPrefill] Preprocess started.'); - $request = \CRM_Utils_Request::retrieve('token', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); + $request = \CRM_Utils_Request::retrieve('token', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); - if (!$request) { - Civi::log()->warning('[AfformPrefill] No token found in URL.'); - return; - } + if (!$request) { + Civi::log()->warning('[AfformPrefill] No token found in URL.'); + return; + } - // Decrypt token - try { - $decrypted = CRM_Utils_Crypt::decrypt($request); - $data = json_decode($decrypted, true); - Civi::log()->debug('[AfformPrefill] Token decrypted: ' . print_r($data, true)); - } catch (\Exception $e) { - Civi::log()->error('[AfformPrefill] Token decryption failed: ' . $e->getMessage()); - return; - } + try { + $decrypted = CRM_Utils_Crypt::decrypt($request); + $data = json_decode($decrypted, true); + Civi::log()->debug('[AfformPrefill] Token decrypted: ' . print_r($data, true)); + } catch (\Exception $e) { + Civi::log()->error('[AfformPrefill] Token decryption failed: ' . $e->getMessage()); + return; + } - if (!is_array($data)) { - Civi::log()->error('[AfformPrefill] Decrypted token is not valid JSON.'); - return; - } + if (!is_array($data)) { + Civi::log()->error('[AfformPrefill] Decrypted token is not valid JSON.'); + return; + } - $changeSet = \Civi\Angular\ChangeSet::create('injectPrefillValues') - ->alterHtml(';\\.aff\\.html$;', function($doc, $path) use ($data) { - Civi::log()->debug("[AfformPrefill] Altering HTML template: {$path}"); + $changeSet = \Civi\Angular\ChangeSet::create('injectPrefillValues') + ->alterHtml(';\\.aff\\.html$;', function ($doc, $path) use ($data) { + Civi::log()->debug("[AfformPrefill] Altering HTML template: {$path}"); - foreach (pq('af-field', $doc) as $afField) { - $fieldName = $afField->getAttribute('name'); + foreach (pq('af-field', $doc) as $afField) { + $fieldName = $afField->getAttribute('name'); - if (!$fieldName) { - continue; - } + if (!$fieldName) { + continue; + } - if (array_key_exists($fieldName, $data)) { - $fieldDefn = self::getFieldDefinition($afField); + if (array_key_exists($fieldName, $data)) { + $fieldDefn = self::getFieldDefinition($afField); - if (!$fieldDefn) { - Civi::log()->warning("[AfformPrefill] No field definition for: {$fieldName}"); - continue; - } + if (!$fieldDefn) { + Civi::log()->warning("[AfformPrefill] No field definition for: {$fieldName}"); + continue; + } - // Inject default value and make read-only - $fieldDefn['afform_default'] = $data[$fieldName]; - $fieldDefn['readonly'] = true; + $fieldDefn['afform_default'] = $data[$fieldName]; + $fieldDefn['readonly'] = true; - pq($afField)->attr('defn', htmlspecialchars(\CRM_Utils_JS::writeObject($fieldDefn), ENT_COMPAT)); - Civi::log()->info("[AfformPrefill] Prefilled field '{$fieldName}' with value: " . json_encode($data[$fieldName])); - } else { - Civi::log()->debug("[AfformPrefill] Field '{$fieldName}' not in token data, skipping."); - } + pq($afField)->attr('defn', htmlspecialchars(\CRM_Utils_JS::writeObject($fieldDefn), ENT_COMPAT)); + Civi::log()->info("[AfformPrefill] Prefilled field '{$fieldName}' with value: " . json_encode($data[$fieldName])); + } else { + Civi::log()->debug("[AfformPrefill] Field '{$fieldName}' not in token data, skipping."); } - }); + } + }); - $event->angular->add($changeSet); - Civi::log()->debug('[AfformPrefill] ChangeSet injected successfully.'); - } + $angular->add($changeSet); + Civi::log()->debug('[AfformPrefill] ChangeSet injected successfully.'); +} public static function getFieldDefinition($afField) { $existingFieldDefn = trim(pq($afField)->attr('defn') ?: ''); diff --git a/wp-content/civi-extensions/goonjcustom/goonjcustom.php b/wp-content/civi-extensions/goonjcustom/goonjcustom.php index 1a620fe63..0e2009edb 100644 --- a/wp-content/civi-extensions/goonjcustom/goonjcustom.php +++ b/wp-content/civi-extensions/goonjcustom/goonjcustom.php @@ -33,6 +33,13 @@ function goonjcustom_civicrm_config(&$config): void { \Civi::dispatcher()->addSubscriber(new CRM_Goonjcustom_Token_IndividualGoonjActivities()); } +/** + * Implements hook_civicrm_alterAngular(). + */ +function goonjcustom_civicrm_alterAngular($angular) { + CRM_Goonjcustom_AfformFieldPrefillService::preprocess($angular); +} + /** * Implements hook_civicrm_install(). * From 58652a4bfbf871247f72e1be45baed9bf4623534 Mon Sep 17 00:00:00 2001 From: belwalshubham Date: Tue, 22 Jul 2025 18:34:14 +0530 Subject: [PATCH 3/3] autofill data --- .../Form/InstitutionDroppingCenterLinks.php | 73 ++++---- .../Civi/DroppingCenterService.php | 15 +- .../Civi/InstitutionDroppingCenterService.php | 70 ++++---- .../goonjcustom/goonjcustom.php | 45 ++++- .../civi-extensions/goonjcustom/js/prefill.js | 163 ++++++++++++++++++ 5 files changed, 298 insertions(+), 68 deletions(-) create mode 100644 wp-content/civi-extensions/goonjcustom/js/prefill.js diff --git a/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php index 7b2630fed..b332c17e7 100644 --- a/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php +++ b/wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php @@ -95,36 +95,47 @@ public function setDefaultValues() { * * @return void */ - public function generateLinks($contactId): void { - $organization = $this->_organization; - $contact = $this->_contact; - - $nameOfInstitution = $organization['display_name']; - $address = $organization['address_primary.street_address']; - $pocEmail = $contact['email.email']; - $pocContactNumber = $contact['phone.phone']; - - // Generate dropping center links. - $links = [ - [ - 'label' => 'Vehicle Dispatch', - 'url' => self::createUrl( - '/institution-dropping-center-vehicle-dispatch', - "Camp_Vehicle_Dispatch.Institution_Dropping_Center={$this->_institutionDroppingCenterId}" . - "&Eck_Collection_Camp1={$this->_institutionDroppingCenterId}" . - "&Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent={$this->_processingCenterId}" . - "&Camp_Vehicle_Dispatch.Filled_by={$contactId}" . - "&Camp_Institution_Data.Name_of_the_institution={$nameOfInstitution}" . - "&Camp_Institution_Data.Address=" . urlencode($address) . - "&Camp_Institution_Data.Email={$pocEmail}" . - "&Camp_Institution_Data.Contact_Number={$pocContactNumber}", - $contactId - ), - ], - ]; - - $this->assign('institutionDroppingCenterLinks', $links); - } + public function generateLinks($contactId): void { + $organization = $this->_organization; + $contact = $this->_contact; + + $nameOfInstitution = $organization['display_name']; + $address = $organization['address_primary.street_address']; + $pocEmail = $contact['email.email']; + $pocContactNumber = $contact['phone.phone']; + + // Create dispatch data array + $dispatchData = [ + 'Camp_Vehicle_Dispatch.Institution_Dropping_Center' => $this->_institutionDroppingCenterId, + 'Camp_Vehicle_Dispatch.Filled_by' => $contactId, + 'Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent' => $this->_processingCenterId, + 'Camp_Vehicle_Dispatch.Goonj_Office_Name' => '', // optional if needed + 'Eck_Collection_Camp1' => $this->_institutionDroppingCenterId, + 'id' => $this->_institutionDroppingCenterId, + 'Camp_Institution_Data.Name_of_the_institution' => $nameOfInstitution, + 'Camp_Institution_Data.Address' => $address, + 'Camp_Institution_Data.Email' => $pocEmail, + 'Camp_Institution_Data.Contact_Number' => $pocContactNumber, + ]; + + // Encrypt token + $json = json_encode($dispatchData); + $encryptedToken = \CRM_Utils_Crypt::encrypt($json); + $tokenParam = 'token=' . urlencode($encryptedToken); + + // Authenticated token + $authUrl = self::createUrl('/institution-dropping-center-vehicle-dispatch', $tokenParam, $contactId); + + // Assign link + $links = [ + [ + 'label' => 'Vehicle Dispatch', + 'url' => $authUrl, + ], + ]; + + $this->assign('institutionDroppingCenterLinks', $links); +} /** * Generate an authenticated URL for viewing this form. @@ -153,7 +164,7 @@ public static function createUrl($path, $params, $contactId): string { $params = "{$params}&_authx={$bearerToken}&_authxSes=1"; // $url = \CRM_Utils_System::url($path, $params, TRUE, NULL, FALSE, TRUE); $config = CRM_Core_Config::singleton(); - $url = $config->userFrameworkBaseURL . $path . '#?' . $params; + $url = $config->userFrameworkBaseURL . $path . '?' . $params; return $url; } diff --git a/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php b/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php index 75ef7235e..891eee601 100644 --- a/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php +++ b/wp-content/civi-extensions/goonjcustom/Civi/DroppingCenterService.php @@ -553,6 +553,7 @@ public static function sendDispatchEmail($email, $initiatorName, $droppingCenter 'Camp_Vehicle_Dispatch.Goonj_Office_Name' => $goonjOfficeName, 'Eck_Collection_Camp1' => $droppingCenterId, 'id' => $droppingCenterId, + 'Dropping_Centre.Where_do_you_wish_to_open_dropping_center_Address_' => 'Hardcoded test address for now' ]; // Step 2: Convert to JSON and encrypt @@ -678,13 +679,13 @@ public static function droppingCenterTabset($tabsetName, &$tabs, $context) { 'template' => 'CRM/Goonjcustom/Tabs/DroppingCenter/DonationBox.tpl', 'permissions' => ['goonj_chapter_admin', 'urbanops', 'urban_ops_admin', 'urban_ops_and_accounts_chapter_team'], ], - 'outcome' => [ - 'title' => ts('Outcome'), - 'module' => 'afsearchDroppingCenterOutcome', - 'directive' => 'afsearch-dropping-center-outcome', - 'template' => 'CRM/Goonjcustom/Tabs/DroppingCenter/Outcome.tpl', - 'permissions' => ['goonj_chapter_admin', 'urbanops', 'urban_ops_admin', 'urban_ops_and_accounts_chapter_team'], - ], + // 'outcome' => [ + // 'title' => ts('Outcome'), + // 'module' => 'afsearchDroppingCenterOutcome', + // 'directive' => 'afsearch-dropping-center-outcome', + // 'template' => 'CRM/Goonjcustom/Tabs/DroppingCenter/Outcome.tpl', + // 'permissions' => ['goonj_chapter_admin', 'urbanops', 'urban_ops_admin', 'urban_ops_and_accounts_chapter_team'], + // ], 'feedback' => [ 'title' => ts('Feedback'), 'module' => 'afsearchFeedback', diff --git a/wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php b/wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php index 493ba5e1c..96fe7fefd 100644 --- a/wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php +++ b/wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php @@ -670,24 +670,34 @@ public static function processDispatchEmail(string $op, string $objectName, $obj /** * */ - public static function sendDispatchEmail($nameOfInstitution, $address, $phone, $email, $initiatorName, $droppingCenterId, $contactId, $goonjOffice, $goonjOfficeName) { - $homeUrl = \CRM_Utils_System::baseCMSURL(); + public static function sendDispatchEmail($nameOfInstitution, $address, $phone, $email, $initiatorName, $droppingCenterId, $contactId, $goonjOffice, $goonjOfficeName) { + $homeUrl = \CRM_Utils_System::baseCMSURL(); + + // Step 1: Gather data + $dispatchData = [ + 'Camp_Vehicle_Dispatch.Institution_Dropping_Center' => $droppingCenterId, + 'Camp_Vehicle_Dispatch.Filled_by' => $contactId, + 'Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent' => $goonjOffice, + 'Camp_Vehicle_Dispatch.Goonj_Office_Name' => $goonjOfficeName, + 'Eck_Collection_Camp1' => $droppingCenterId, + 'id' => $droppingCenterId, + 'Camp_Institution_Data.Name_of_the_institution' => $nameOfInstitution, + 'Camp_Institution_Data.Address' => $address, + 'Camp_Institution_Data.Email' => $email, + 'Camp_Institution_Data.Contact_Number' => $phone, + ]; + + // Step 2: Convert to JSON and encrypt + $json = json_encode($dispatchData); + $token = \CRM_Utils_Crypt::encrypt($json); - $baseUrl = '/institution-dropping-center-vehicle-dispatch/'; - - $vehicleDispatchFormUrl = $homeUrl . $baseUrl . '#?Camp_Vehicle_Dispatch.Institution_Dropping_Center=' . $droppingCenterId - . '&Camp_Vehicle_Dispatch.Filled_by=' . $contactId - . '&Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent=' . $goonjOffice - . '&Camp_Vehicle_Dispatch.Goonj_Office_Name=' . $goonjOfficeName - . '&Eck_Collection_Camp1=' . $droppingCenterId - . '&Camp_Institution_Data.Name_of_the_institution=' . $nameOfInstitution - . "&Camp_Institution_Data.Address=" . urlencode($address) - . "&Camp_Institution_Data.Email=" . $email - . "&Camp_Institution_Data.Contact_Number=" . $phone; - - $emailHtml = " - - + // Step 3: Generate encrypted URL + $vehicleDispatchFormUrl = $homeUrl . '/institution-dropping-center-vehicle-dispatch/?token=' . urlencode($token); + + // Step 4: Compose HTML email + $emailHtml = " + +

Dear {$initiatorName},

Thank you so much for your invaluable efforts in running the Goonj Dropping Center. Your dedication plays a crucial role in our work, and we deeply appreciate your continued support.

@@ -695,19 +705,21 @@ public static function sendDispatchEmail($nameOfInstitution, $address, $phone, $ This will help us to verify and acknowledge the materials as soon as they arrive.

We truly appreciate your cooperation and continued commitment to our cause.

Warm Regards,
Team Goonj..

- - - "; - $from = HelperService::getDefaultFromEmail(); - $mailParams = [ - 'subject' => 'Kindly fill the Dispatch Form for Material Pickup', - 'from' => $from, - 'toEmail' => $email, - 'html' => $emailHtml, - ]; + + + "; + + // Step 5: Send email + $from = HelperService::getDefaultFromEmail(); + $mailParams = [ + 'subject' => 'Kindly fill the Dispatch Form for Material Pickup', + 'from' => $from, + 'toEmail' => $email, + 'html' => $emailHtml, + ]; - \CRM_Utils_Mail::send($mailParams); - } + \CRM_Utils_Mail::send($mailParams); +} /** * diff --git a/wp-content/civi-extensions/goonjcustom/goonjcustom.php b/wp-content/civi-extensions/goonjcustom/goonjcustom.php index 0e2009edb..9058088aa 100644 --- a/wp-content/civi-extensions/goonjcustom/goonjcustom.php +++ b/wp-content/civi-extensions/goonjcustom/goonjcustom.php @@ -37,9 +37,47 @@ function goonjcustom_civicrm_config(&$config): void { * Implements hook_civicrm_alterAngular(). */ function goonjcustom_civicrm_alterAngular($angular) { - CRM_Goonjcustom_AfformFieldPrefillService::preprocess($angular); + Civi::log()->debug('[AfformPrefill] alterAngular hook called'); + + $token = \CRM_Utils_Request::retrieve('token', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); + Civi::log()->debug('[AfformPrefill] Token: ' . ($token ? $token : '(none)')); + if (!$token) { + Civi::log()->debug('[AfformPrefill] No token, skipping prefill.'); + return; + } + + try { + $decrypted = \CRM_Utils_Crypt::decrypt($token); + Civi::log()->debug('[AfformPrefill] Decrypted: ' . $decrypted); + $data = json_decode($decrypted, true); + Civi::log()->debug('[AfformPrefill] Parsed array: ' . print_r($data, 1)); + } catch (\Exception $e) { + Civi::log()->error('[AfformPrefill] Token decryption failed: ' . $e->getMessage()); + return; + } + + if (!is_array($data)) { + Civi::log()->error('[AfformPrefill] Decrypted data is not an array.'); + return; + } + + $prefillData = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT); + \Civi::resources()->addScriptFile('goonjcustom', 'js/prefill.js', 10, 'html-header'); + + + \Civi::log()->debug('[AfformPrefill] JavaScript prefill payload: ' . $prefillData); + + \Civi::resources()->addScript(" + (function() { + if (window.CRM === undefined) window.CRM = {}; + window.CRM.afformPrefillData = $prefillData; + console.log('[AfformPrefill] Prefill data available on window.CRM.afformPrefillData:', window.CRM.afformPrefillData); + })(); + ", 10, 'html-header'); } + + /** * Implements hook_civicrm_install(). * @@ -49,6 +87,11 @@ function goonjcustom_civicrm_install(): void { _goonjcustom_civix_civicrm_install(); } + + + + + /** * Implements hook_civicrm_enable(). * diff --git a/wp-content/civi-extensions/goonjcustom/js/prefill.js b/wp-content/civi-extensions/goonjcustom/js/prefill.js new file mode 100644 index 000000000..549fc06c3 --- /dev/null +++ b/wp-content/civi-extensions/goonjcustom/js/prefill.js @@ -0,0 +1,163 @@ +(function () { + console.log('[AfformPrefill] Script with logs and EntityRef + dependent autofill loaded'); + + function setNested(obj, path, value) { + const parts = path.split('.'); + let current = obj; + for (let i = 0; i < parts.length - 1; i++) { + if (!current[parts[i]]) current[parts[i]] = {}; + current = current[parts[i]]; + } + current[parts[parts.length - 1]] = value; + } + + function flattenObject(obj, prefix = '', result = {}) { + Object.keys(obj).forEach(function (key) { + const value = obj[key]; + const newKey = prefix ? `${prefix}.${key}` : key; + if (value && typeof value === 'object' && !Array.isArray(value)) { + flattenObject(value, newKey, result); + } else { + result[newKey] = value; + } + }); + return result; + } + + function waitForAngularAndPrefill(retries = 100) { + if (!(window.angular && window.angular.module)) { + if (retries <= 0) return console.error('[AfformPrefill] Angular not found'); + return setTimeout(() => waitForAngularAndPrefill(retries - 1), 200); + } + pollForFormAndPrefill(); + } + + function pollForFormAndPrefill(retries = 100) { + const formElem = document.querySelector('[af-form], [af-fieldset], .crm-afform-form, .af-container'); + if (!formElem) { + if (retries <= 0) return console.error('[AfformPrefill] Form not found'); + return setTimeout(() => pollForFormAndPrefill(retries - 1), 200); + } + + const scope = angular.element(formElem).scope(); + if (!scope) { + if (retries <= 0) return console.error('[AfformPrefill] Scope not found'); + return setTimeout(() => pollForFormAndPrefill(retries - 1), 200); + } + + if (scope._afformPrefilled) { + console.log('[AfformPrefill] Already prefilled ✅'); + return; + } + + const data = window.CRM?.afformPrefillData; + if (!data) return console.warn('[AfformPrefill] No afformPrefillData found ❗'); + + const $timeout = angular.element(formElem).injector().get('$timeout'); + const $rootScope = angular.element(formElem).injector().get('$rootScope'); + + $timeout(function () { + const flattened = flattenObject(data); + const scopePaths = ['data', 'model', 'formData', 'entity']; + + console.log('[AfformPrefill] Flattened keys:', Object.keys(flattened)); + + // Set values in Angular scope + scopePaths.forEach(path => { + if (!scope[path]) scope[path] = {}; + Object.entries(flattened).forEach(([key, value]) => { + setNested(scope[path], key, value); + console.log(`[AfformPrefill] Set scope.${path}.${key} =`, value); + }); + }); + + scopePaths.forEach(path => { + Object.keys(scope[path]).forEach(entity => { + if (entity === 'Camp_Institution_Data' && typeof scope[path][entity] === 'object' && !Array.isArray(scope[path][entity])) { + console.log(`[AfformPrefill] Wrapping ${path}.${entity} as array for join compatibility`); + scope[path][entity] = [scope[path][entity]]; + } + }); + }); + + // Autofill standard input fields + const inputs = formElem.querySelectorAll('input, select, textarea'); + console.log('[AfformPrefill] Total fields to check:', inputs.length); + inputs.forEach((field) => { + const fieldName = field.name || field.getAttribute('name'); + const ngModel = field.getAttribute('ng-model'); + const id = field.id || ''; + const fieldKey = ngModel?.replace(/^.*?entity\./, '') || fieldName || id; + + const matchedKey = Object.keys(flattened).find(k => + k === fieldKey || k.endsWith('.' + fieldKey) || (fieldKey && k.includes(fieldKey)) + ); + + if (!matchedKey) { + console.warn(`[AfformPrefill] No match found for field:`, { fieldName, ngModel, id }); + return; + } + + const value = flattened[matchedKey]; + console.log(`[AfformPrefill] ✅ Matched ${matchedKey} →`, value); + + try { + if (field.tagName.toLowerCase() === 'select') { + field.value = value; + } else if (field.type === 'checkbox') { + field.checked = !!value; + } else if (field.type === 'radio') { + if (field.value == value) field.checked = true; + } else { + field.value = value; + } + + ['input', 'change', 'blur'].forEach(evt => { + const e = new Event(evt, { bubbles: true }); + field.dispatchEvent(e); + angular.element(field).triggerHandler(evt); + }); + + console.log(`[AfformPrefill] Value set on DOM field [${fieldKey}]`); + + } catch (err) { + console.error(`[AfformPrefill] Error setting field [${fieldKey}]`, err.message); + } + }); + + document.querySelectorAll('.ng-isolate-scope').forEach(function (afFieldElem) { + const fieldName = afFieldElem.getAttribute('name'); + const flatData = flattenObject(window.CRM.afformPrefillData); + if (!flatData[fieldName]) { + console.warn(`[EntityRef] No data to prefill for ${fieldName}`); + return; + } + + const value = flatData[fieldName]; + const isolateScope = angular.element(afFieldElem).isolateScope(); + const model = isolateScope?.getSetSelect; + + if (typeof model === 'function') { + console.log(`[EntityRef] Setting ${fieldName} →`, value); + model(value); + + if (typeof isolateScope?.$ctrl?.onSelectEntity === 'function') { + isolateScope.$ctrl.onSelectEntity(); + console.log(`[EntityRef] onSelectEntity() triggered for ${fieldName}`); + } + + isolateScope.$applyAsync?.(); + } else { + console.warn(`[EntityRef] getSetSelect not found for ${fieldName}`); + } + }); + + scope._afformPrefilled = true; + try { scope.$apply(); $rootScope.$apply(); } catch (_) {} + + console.log('[AfformPrefill]Autofill completed!'); + }, 1000); + } + + waitForAngularAndPrefill(); +})();