From d8bb82a11dd0cde6efcab9d8df8bf4b4e1c63c4c Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Tue, 26 Mar 2024 12:18:11 -0300 Subject: [PATCH 01/25] feature: add phone column to donors table --- src/Donors/Migrations/addPhoneColumn.php | 60 ++++++++++++++++++++++++ src/Donors/ServiceProvider.php | 6 +++ 2 files changed, 66 insertions(+) create mode 100644 src/Donors/Migrations/addPhoneColumn.php diff --git a/src/Donors/Migrations/addPhoneColumn.php b/src/Donors/Migrations/addPhoneColumn.php new file mode 100644 index 0000000000..7bef258db9 --- /dev/null +++ b/src/Donors/Migrations/addPhoneColumn.php @@ -0,0 +1,60 @@ +prefix}give_donors"; + + try { + maybe_add_column( + $donorsTableName, + 'phone', + "ALTER TABLE `$donorsTableName` ADD COLUMN `phone` varchar(50) NOT NULL DEFAULT '' AFTER `email`" + ); + } catch (DatabaseQueryException $exception) { + throw new DatabaseMigrationException('An error occurred adding the phone column to the donors table', + 0, $exception); + } + } + + /** + * @unreleased + */ + public static function id(): string + { + return 'donors-add-phone-column'; + } + + /** + * @unreleased + */ + public static function title(): string + { + return 'Add phone column to donors table'; + } + + /** + * @unreleased + */ + public static function timestamp() + { + return strtotime('2024-26-03'); + } +} diff --git a/src/Donors/ServiceProvider.php b/src/Donors/ServiceProvider.php index 1b0eabb364..c4b01f61ee 100644 --- a/src/Donors/ServiceProvider.php +++ b/src/Donors/ServiceProvider.php @@ -8,8 +8,10 @@ use Give\Donors\CustomFields\Controllers\DonorDetailsController; use Give\Donors\Exceptions\FailedDonorUserCreationException; use Give\Donors\ListTable\DonorsListTable; +use Give\Donors\Migrations\addPhoneColumn; use Give\Donors\Models\Donor; use Give\Donors\Repositories\DonorRepositoryProxy; +use Give\Framework\Migrations\MigrationsRegister; use Give\Helpers\Hooks; use Give\Log\Log; use Give\ServiceProviders\ServiceProvider as ServiceProviderInterface; @@ -55,6 +57,10 @@ public function boot() $this->addCustomFieldsToDonorDetails(); $this->enforceDonorsAsUsers(); + + give(MigrationsRegister::class)->addMigrations([ + addPhoneColumn::class, + ]); } /** From cc00b045a73661eb0221409aa1739b236b35fb2d Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Tue, 26 Mar 2024 14:00:49 -0300 Subject: [PATCH 02/25] feature: add donor phone to model and repository --- src/Donors/DataTransferObjects/DonorQueryData.php | 5 +++++ src/Donors/Factories/DonorFactory.php | 1 + src/Donors/Models/Donor.php | 2 ++ src/Donors/Repositories/DonorRepository.php | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/Donors/DataTransferObjects/DonorQueryData.php b/src/Donors/DataTransferObjects/DonorQueryData.php index f9200908d0..63e0746871 100644 --- a/src/Donors/DataTransferObjects/DonorQueryData.php +++ b/src/Donors/DataTransferObjects/DonorQueryData.php @@ -31,6 +31,10 @@ final class DonorQueryData * @var string */ public $email; + /** + * @var string + */ + public $phone; /** * @var string */ @@ -77,6 +81,7 @@ public static function fromObject($object) $self->userId = (int)$object->userId; $self->prefix = $object->{DonorMetaKeys::PREFIX()->getKeyAsCamelCase()}; $self->email = $object->email; + $self->phone = $object->phone; $self->name = $object->name; $self->firstName = $object->firstName; $self->lastName = $object->lastName; diff --git a/src/Donors/Factories/DonorFactory.php b/src/Donors/Factories/DonorFactory.php index 177ca392e6..07eb1584ae 100644 --- a/src/Donors/Factories/DonorFactory.php +++ b/src/Donors/Factories/DonorFactory.php @@ -19,6 +19,7 @@ public function definition(): array 'lastName' => $lastName, 'name' => trim("$firstName $lastName"), 'email' => $this->faker->email, + 'phone' => $this->faker->phoneNumber, 'totalAmountDonated' => new Money(0, 'USD'), 'totalNumberOfDonations' => 0 ]; diff --git a/src/Donors/Models/Donor.php b/src/Donors/Models/Donor.php index 2793acc36f..63af16e31e 100644 --- a/src/Donors/Models/Donor.php +++ b/src/Donors/Models/Donor.php @@ -31,6 +31,7 @@ * @property string $firstName * @property string $lastName * @property string $email + * @property string $phone * @property string[] $additionalEmails * @property Money $totalAmountDonated * @property int $totalNumberOfDonations @@ -50,6 +51,7 @@ class Donor extends Model implements ModelCrud, ModelHasFactory 'firstName' => 'string', 'lastName' => 'string', 'email' => 'string', + 'phone' => 'string', 'prefix' => 'string', 'additionalEmails' => ['array', []], 'totalAmountDonated' => Money::class, diff --git a/src/Donors/Repositories/DonorRepository.php b/src/Donors/Repositories/DonorRepository.php index d9aaccc468..096ffbb47a 100644 --- a/src/Donors/Repositories/DonorRepository.php +++ b/src/Donors/Repositories/DonorRepository.php @@ -119,6 +119,7 @@ public function insert(Donor $donor) 'date_created' => Temporal::getFormattedDateTime($dateCreated), 'user_id' => $donor->userId ?? 0, 'email' => $donor->email, + 'phone' => $donor->phone, 'name' => $donor->name, ]; @@ -192,6 +193,7 @@ public function update(Donor $donor) $args = [ 'user_id' => $donor->userId, 'email' => $donor->email, + 'phone' => $donor->phone, 'name' => $donor->name ]; @@ -381,6 +383,7 @@ public function prepareQuery(): DonorModelQueryBuilder 'id', ['user_id', 'userId'], 'email', + 'phone', 'name', ['purchase_value', 'totalAmountDonated'], ['purchase_count', 'totalNumberOfDonations'], From 3af83fd063d0889de98043003436ac08e29ba634 Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Tue, 26 Mar 2024 14:02:05 -0300 Subject: [PATCH 03/25] feature: add phone to donor profile page --- includes/admin/donors/donor-actions.php | 6 ++++++ includes/admin/donors/donors.php | 28 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/includes/admin/donors/donor-actions.php b/includes/admin/donors/donor-actions.php index b8538e36f4..cb730589fb 100644 --- a/includes/admin/donors/donor-actions.php +++ b/includes/admin/donors/donor-actions.php @@ -10,6 +10,8 @@ */ // Exit if accessed directly. +use Give\Donors\Models\Donor; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -124,6 +126,10 @@ function give_edit_donor( $args ) { // Save company name in when admin update donor company name from dashboard. $donor->update_meta( '_give_donor_company', sanitize_text_field( $args['give_donor_company'] ) ); + $donorModel = Donor::find($donor->id); + $donorModel->phone = sanitize_text_field($args['give_donor_phone_number']); + $donorModel->save(); + // If First name of donor is empty, then fetch the current first name of donor. if ( empty( $donor_info['first_name'] ) ) { $donor_info['first_name'] = $donor->get_first_name(); diff --git a/includes/admin/donors/donors.php b/includes/admin/donors/donors.php index 55f67ffcdd..4ec68a92dd 100644 --- a/includes/admin/donors/donors.php +++ b/includes/admin/donors/donors.php @@ -9,6 +9,8 @@ * @since 1.0 */ +use Give\Donors\Models\Donor; + // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; @@ -478,10 +480,32 @@ function give_donor_view( $donor ) { - id)->phone; + ?> + + + + + + + + + + + + + + + + get_meta( '_give_donor_company', true ); ?> - + From 69974c431f1a5a74c9f90add14a654a2e0e1dc17 Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Tue, 26 Mar 2024 18:08:34 -0300 Subject: [PATCH 04/25] feature: add give_get_phone_input method with support for international numbers --- includes/admin/donors/donor-actions.php | 2 +- includes/admin/donors/donors.php | 5 +- includes/misc-functions.php | 84 +++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/includes/admin/donors/donor-actions.php b/includes/admin/donors/donor-actions.php index cb730589fb..41e0ea9a94 100644 --- a/includes/admin/donors/donor-actions.php +++ b/includes/admin/donors/donor-actions.php @@ -127,7 +127,7 @@ function give_edit_donor( $args ) { $donor->update_meta( '_give_donor_company', sanitize_text_field( $args['give_donor_company'] ) ); $donorModel = Donor::find($donor->id); - $donorModel->phone = sanitize_text_field($args['give_donor_phone_number']); + $donorModel->phone = sanitize_text_field($args['give_donor_phone_number--full_number']); $donorModel->save(); // If First name of donor is empty, then fetch the current first name of donor. diff --git a/includes/admin/donors/donors.php b/includes/admin/donors/donors.php index 4ec68a92dd..bbbdc9824a 100644 --- a/includes/admin/donors/donors.php +++ b/includes/admin/donors/donors.php @@ -491,8 +491,8 @@ function give_donor_view( $donor ) { - + @@ -501,7 +501,6 @@ function give_donor_view( $donor ) { - get_meta( '_give_donor_company', true ); ?> diff --git a/includes/misc-functions.php b/includes/misc-functions.php index 9b4faac62a..f224d73bb5 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2624,3 +2624,87 @@ function give_get_page_by_title(string $page_title, string $output = OBJECT, str return get_post($pages[0], $output); } + + /** + * @see https://github.com/jackocnr/intl-tel-input + * + * @unreleased + */ +function give_get_phone_input(string $value, string $id, string $name = ''):string { + + if (empty($name)) { + $name = $id; + } + + /*$handle = 'intlTelInput'; + + wp_enqueue_style( + $handle, + 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/css/intlTelInput.css', + [], + '20.2.0' + ); + + wp_enqueue_script( + $handle, + 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/js/intlTelInput.min.js', + [], + '20.2.0', + true + ); + + wp_add_inline_script( $handle, ' + const input = document.querySelector("#' . $id . '"); + window.intlTelInput(input, { + initialCountry: "' . give_get_country() . '", + showSelectedDialCode: true, + //strictMode: true, + utilsScript: "https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/js/utils.js", + }); + ' ); + + return "";*/ + + ob_start(); + + ?> + + + + + + Date: Wed, 27 Mar 2024 09:59:08 -0300 Subject: [PATCH 05/25] refactor: make country list translatable --- includes/misc-functions.php | 54 ++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/includes/misc-functions.php b/includes/misc-functions.php index f224d73bb5..e043d16a55 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2636,24 +2636,32 @@ function give_get_phone_input(string $value, string $id, string $name = ''):stri $name = $id; } - /*$handle = 'intlTelInput'; + $styleUrl = 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/css/intlTelInput.css'; + $scriptUrl = 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/js/intlTelInput.min.js'; + $utilsScriptUrl = 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/js/utils.js'; + + /* $handle = 'intlTelInput'; + $version = '20.2.0'; wp_enqueue_style( $handle, - 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/css/intlTelInput.css', + $styleUrl, [], - '20.2.0' + $version ); wp_enqueue_script( $handle, - 'https://cdn.jsdelivr.net/npm/intl-tel-input@20.2.0/build/js/intlTelInput.min.js', + $scriptUrl, [], - '20.2.0', + $version, true ); - wp_add_inline_script( $handle, ' + + + + wp_add_inline_script( $handle, ' const input = document.querySelector("#' . $id . '"); window.intlTelInput(input, { initialCountry: "' . give_get_country() . '", @@ -2665,18 +2673,22 @@ function give_get_phone_input(string $value, string $id, string $name = ''):stri return "";*/ + $countryList = give_get_country_list(); + array_shift($countryList); + $countryList = json_encode($countryList); + ob_start(); ?> - - + + + From ad2eb97cbd10bb8fc6809ca5823c231bd2578865 Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 13:14:02 -0300 Subject: [PATCH 06/25] fix: case for country list key --- includes/misc-functions.php | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/includes/misc-functions.php b/includes/misc-functions.php index e043d16a55..6d2d1f1c02 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2673,10 +2673,20 @@ function give_get_phone_input(string $value, string $id, string $name = ''):stri return "";*/ - $countryList = give_get_country_list(); + $initialCountry = strtolower(give_get_country()); + + $countryList = array_change_key_case(give_get_country_list()); array_shift($countryList); $countryList = json_encode($countryList); + $selectedCountryAriaLabel = __('Selected country', 'give'); // Aria label for the selected country element + $noCountrySelected = __('No country selected', 'give'); // Screen reader text for when no country is selected + $countryListAriaLabel = __('List of countries', 'give'); // Aria label for the country list element + $searchPlaceholder = __('Search', 'give'); // Placeholder for the search input in the dropdown (when countrySearch enabled) + $zeroSearchResults = __('No results found', 'give'); // Screen reader text for when the search produces no results + $oneSearchResult = __('1 result found', 'give'); // Screen reader text for when the search produces 1 result + $multipleSearchResults = __('${count} results found', 'give'); // Screen reader text for when the search produces multiple results, where ${count} will be replaced by the count + ob_start(); ?> @@ -2695,18 +2705,18 @@ function give_get_phone_input(string $value, string $id, string $name = ''):stri country: "" }; }, - initialCountry: "", + initialCountry: "", showSelectedDialCode: true, strictMode: true, i18n: { ..., - selectedCountryAriaLabel: "", // Aria label for the selected country element - noCountrySelected: "", // Screen reader text for when no country is selected - countryListAriaLabel: "", // Aria label for the country list element - searchPlaceholder: "", // Placeholder for the search input in the dropdown (when countrySearch enabled) - zeroSearchResults: "", // Screen reader text for when the search produces no results - oneSearchResult: "", // Screen reader text for when the search produces 1 result - multipleSearchResults: "", // Screen reader text for when the search produces multiple results, where ${count} will be replaced by the count + selectedCountryAriaLabel: "", + noCountrySelected: "", + countryListAriaLabel: "", + searchPlaceholder: "", + zeroSearchResults: "", + oneSearchResult: "", + multipleSearchResults: "", } }); From ecf28ee7891aaf332e03981f21202147c764bf8f Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 13:25:44 -0300 Subject: [PATCH 07/25] fix: change js logic to allow multiple input in a same page --- includes/misc-functions.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/misc-functions.php b/includes/misc-functions.php index 6d2d1f1c02..76ae9557e8 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2696,8 +2696,7 @@ function give_get_phone_input(string $value, string $id, string $name = ''):stri __('Selected country', 'give'), // Aria label for the selected country element + 'noCountrySelected' => __('No country selected', 'give'), // Screen reader text for when no country is selected + 'countryListAriaLabel' => __('List of countries', 'give'), // Aria label for the country list element + 'searchPlaceholder' => __('Search', 'give'), // Placeholder for the search input in the dropdown (when countrySearch enabled) + 'zeroSearchResults' => __('No results found', 'give'), // Screen reader text for when the search produces no results + 'oneSearchResult' => __('1 result found', 'give'), // Screen reader text for when the search produces 1 result + 'multipleSearchResults' => __('${count} results found', 'give'), // Screen reader text for when the search produces multiple results, where ${count} will be replaced by the count + ]; + + $i18n = array_merge($countryList, $i18n); + + return json_encode($i18n); +} From 4a0ad380795afe3a0431cb811e23a113242cae8c Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 13:52:33 -0300 Subject: [PATCH 09/25] refactor: add support to custom classes in the tel input --- includes/misc-functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/misc-functions.php b/includes/misc-functions.php index abb7057222..086965413a 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2630,7 +2630,7 @@ function give_get_page_by_title(string $page_title, string $output = OBJECT, str * * @unreleased */ -function give_get_intl_tel_input(string $value, string $id, string $name = ''):string { +function give_get_intl_tel_input(string $value, string $id, string $class = '', string $name = ''):string { if (empty($name)) { $name = $id; @@ -2643,7 +2643,7 @@ function give_get_intl_tel_input(string $value, string $id, string $name = ''):s ob_start(); ?> - + From 1e793b5f236ce4fb186ea7057bc84dd57e39318d Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 15:36:46 -0300 Subject: [PATCH 10/25] feature: add logic to validate phone numbers --- includes/misc-functions.php | 110 ++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/includes/misc-functions.php b/includes/misc-functions.php index 086965413a..d1cbeea40b 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2643,25 +2643,75 @@ function give_get_intl_tel_input(string $value, string $id, string $class = '', ob_start(); ?> - - - + + + + + __('Selected country', 'give'), // Aria label for the selected country element - 'noCountrySelected' => __('No country selected', 'give'), // Screen reader text for when no country is selected - 'countryListAriaLabel' => __('List of countries', 'give'), // Aria label for the country list element - 'searchPlaceholder' => __('Search', 'give'), // Placeholder for the search input in the dropdown (when countrySearch enabled) - 'zeroSearchResults' => __('No results found', 'give'), // Screen reader text for when the search produces no results - 'oneSearchResult' => __('1 result found', 'give'), // Screen reader text for when the search produces 1 result - 'multipleSearchResults' => __('${count} results found', 'give'), // Screen reader text for when the search produces multiple results, where ${count} will be replaced by the count - ]; + $countryList = array_change_key_case(give_get_country_list()); + array_shift($countryList); // Remove first empty item from the country list + + $i18n = [ + 'selectedCountryAriaLabel' => __('Selected country', 'give'), // Aria label for the selected country element + 'noCountrySelected' => __('No country selected', 'give'), // Screen reader text for when no country is selected + 'countryListAriaLabel' => __('List of countries', 'give'), // Aria label for the country list element + 'searchPlaceholder' => __('Search', 'give'), // Placeholder for the search input in the dropdown (when countrySearch enabled) + 'zeroSearchResults' => __('No results found', 'give'), // Screen reader text for when the search produces no results + 'oneSearchResult' => __('1 result found', 'give'), // Screen reader text for when the search produces 1 result + 'multipleSearchResults' => __('${count} results found', 'give'), // Screen reader text for when the search produces multiple results, where ${count} will be replaced by the count + ]; - $i18n = array_merge($countryList, $i18n); + $i18n = array_merge($countryList, $i18n); - return json_encode($i18n); + return json_encode($i18n); } From fcd761ea7124581a5cad204e9d34ee6482b18885 Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 15:57:51 -0300 Subject: [PATCH 11/25] fix: save phone on DB as empty when it's null --- src/Donors/Repositories/DonorRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Donors/Repositories/DonorRepository.php b/src/Donors/Repositories/DonorRepository.php index 096ffbb47a..7faf123d63 100644 --- a/src/Donors/Repositories/DonorRepository.php +++ b/src/Donors/Repositories/DonorRepository.php @@ -119,7 +119,7 @@ public function insert(Donor $donor) 'date_created' => Temporal::getFormattedDateTime($dateCreated), 'user_id' => $donor->userId ?? 0, 'email' => $donor->email, - 'phone' => $donor->phone, + 'phone' => $donor->phone ?? '', 'name' => $donor->name, ]; From 723bf6f4fa3d158367ab309dfc9db2ddc4fdea3b Mon Sep 17 00:00:00 2001 From: Glauber Silva Date: Wed, 27 Mar 2024 16:02:28 -0300 Subject: [PATCH 12/25] refactor: rename hidden inputs --- includes/admin/donors/donor-actions.php | 2 +- includes/misc-functions.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/admin/donors/donor-actions.php b/includes/admin/donors/donor-actions.php index 41e0ea9a94..619455b098 100644 --- a/includes/admin/donors/donor-actions.php +++ b/includes/admin/donors/donor-actions.php @@ -127,7 +127,7 @@ function give_edit_donor( $args ) { $donor->update_meta( '_give_donor_company', sanitize_text_field( $args['give_donor_company'] ) ); $donorModel = Donor::find($donor->id); - $donorModel->phone = sanitize_text_field($args['give_donor_phone_number--full_number']); + $donorModel->phone = sanitize_text_field($args['give_donor_phone_number--international-format']); $donorModel->save(); // If First name of donor is empty, then fetch the current first name of donor. diff --git a/includes/misc-functions.php b/includes/misc-functions.php index d1cbeea40b..d39494a722 100644 --- a/includes/misc-functions.php +++ b/includes/misc-functions.php @@ -2647,7 +2647,7 @@ function give_get_intl_tel_input(string $value, string $id, string $class = '', - +