Plugin Directory

Changeset 3286617


Ignore:
Timestamp:
05/03/2025 03:56:09 AM (11 months ago)
Author:
dashcommerce
Message:

1.3.4

Location:
dashcommerce/trunk
Files:
6 added
8 edited

Legend:

Unmodified
Added
Removed
  • dashcommerce/trunk/dashcommerce.php

    r3276913 r3286617  
    1212 * Plugin Name: DashCommerce - Support, Checkup, Optimization, AI, Reports & Analytics
    1313 * Description: Keep your website healthy and efficient with DashCommerce.
    14  * Version: 1.3.3
     14 * Version: 1.3.4
    1515 * Author: DashCommerce
    1616 * License: GPL v2
  • dashcommerce/trunk/features/diagnostics/class-diagnostics.php

    r3275268 r3286617  
    128128        wp_enqueue_script( 'luxon', plugin_dir_url( __FILE__ ) . '../../assets/js/luxon.min.js', array(), '3.5.0', true );
    129129        wp_enqueue_script( 'luxon-adapter', plugin_dir_url( __FILE__ ) . '../../assets/js/chartjs-adapter-luxon.umd.js', array(), '1.3.1', true );
     130
     131        wp_enqueue_script( 'iti', plugin_dir_url( __FILE__ ) . '../../assets/js/intl-tel-input/intlTelInputWithUtils.min.js', array(), '25.3.1', true );
     132        wp_script_add_data( 'iti', 'type', 'module' );
     133
     134        wp_enqueue_style( 'iti-styles', plugin_dir_url( __FILE__ ) . '../../assets/js/intl-tel-input/intlTelInput.css', array(), '25.3.1' );
    130135
    131136        wp_enqueue_script( 'dashcommerce-diagnostics-js', plugin_dir_url( __FILE__ ) . 'diagnostics.js', array( 'jquery', 'dashcommerce-utils-js' ), $ver, true );
     
    148153                'scheduled'   => $this->cron_schedule(),
    149154                'req_phone'   => ! $this->account->get_phone(),
     155                'country'     => $this->utils->get_site_country(),
    150156            )
    151157        );
     
    219225
    220226                    <div style="margin: 10px 0;">
    221                         <input type="tel" id="dashcommerce-diagnostics-phone-modal-input" name="phone" placeholder="(XX) XXXXX-XXXX">
     227                        <input type="tel" id="dashcommerce-diagnostics-phone-modal-input">
    222228                    </div>
    223229
     
    227233                        </div>
    228234
    229                         <button id="dashcommerce-diagnostics-phone-modal-continue" class="button dashcommerce-button">
     235                        <button id="dashcommerce-diagnostics-phone-modal-continue" class="button dashcommerce-button" disabled="disabled">
    230236                            Gerar diagnóstico
    231237                        </button>
     
    791797        $phone = isset( $_POST['phone'] ) ? sanitize_text_field( wp_unslash( $_POST['phone'] ) ) : null;
    792798
     799        $phone = preg_replace( '/\D/', '', $phone );
     800
    793801        if ( is_null( $phone ) ) {
    794802            wp_send_json(
  • dashcommerce/trunk/features/diagnostics/diagnostics.js

    r3275268 r3286617  
    4848                continue: jQuery('#dashcommerce-diagnostics-phone-modal-continue'),
    4949                saving: jQuery('#dashcommerce-diagnostics-phone-modal-spinner-saving'),
     50                inputITI: null,
    5051            }
    5152        }
     
    103104        },
    104105        savePhone: async (phone) => {
    105             if (!phone || !dashcommerce_utils.validateBrPhone(phone)) {
    106                 throw new Error('Please enter a valid phone number.');
    107             }
    108 
    109106            this.setSaving(true);
    110107
     
    226223
    227224        this.elements.modals.phone.continue.on('click', async () => {
    228             const phone = this.elements.modals.phone.input.val();
     225            const phone = this.elements.modals.phone.inputITI.getNumber(window['intlTelInput'].utils.numberFormat.INTERNATIONAL);
    229226
    230227            if (typeof phone !== 'string' || phone.length === 0) {
     
    233230            }
    234231
     232            const isValid = this.elements.modals.phone.inputITI.isValidNumber();
     233
     234            if (!isValid) {
     235                const errorCode = this.elements.modals.phone.inputITI.getValidationError();
     236
     237                alert(`Please enter a valid phone number.`);
     238
     239                console.error(`[DashCommerce] Phone number '${phone} 'is invalid: code ${errorCode}`);
     240
     241                return;
     242            }
     243
    235244            try {
    236245                this.elements.modals.phone.saving.show();
     246                this.elements.modals.phone.continue.attr('disabled', 'disabled');
     247
    237248                await this.requests.savePhone(phone);
    238                 this.elements.modals.phone.saving.hide();
    239249            }
    240250            catch (error) {
    241                 this.elements.modals.phone.saving.hide();
    242251                alert(error.message);
    243252                return;
     253            }
     254            finally {
     255                this.elements.modals.phone.saving.hide();
     256                this.elements.modals.phone.continue.removeAttr('disabled');
    244257            }
    245258
     
    296309
    297310        this.charts.line('scoreHistoryLineChart', dashcommerce_vars_diagnostics?.history);
     311
     312        this.elements.modals.phone.inputITI = dashcommerce_utils.initializeItiField(
     313            this.elements.modals.phone.input.get(0),
     314            dashcommerce_vars_diagnostics?.country,
     315            this.elements.modals.phone.continue.get(0)
     316        );
    298317    }
    299318
  • dashcommerce/trunk/features/reports/class-reports.php

    r3275268 r3286617  
    6060        $ver = $dashcommerce_utils->get_plugin_version();
    6161
     62        wp_enqueue_script( 'iti', plugin_dir_url( __FILE__ ) . '../../assets/js/intl-tel-input/intlTelInputWithUtils.min.js', array(), '25.3.1', true );
     63        wp_script_add_data( 'iti', 'type', 'module' );
     64
     65        wp_enqueue_style( 'iti-styles', plugin_dir_url( __FILE__ ) . '../../assets/js/intl-tel-input/intlTelInput.css', array(), '25.3.1' );
     66
    6267        wp_enqueue_script( 'dashcommerce-reports-page-js', plugin_dir_url( __FILE__ ) . 'script-reports.js', array( 'jquery', 'dashcommerce-utils-js' ), $ver, true );
    6368
     
    6974                'nonce'    => wp_create_nonce( 'dashcommerce_nonce' ),
    7075                'settings' => $dashcommerce_settings->get_settings(),
     76                'country'  => $this->utils->get_site_country(),
    7177            )
    7278        );
     
    183189                        <div>
    184190                            <label>Números de WhatsApp:</label>
    185                             <input style="margin-right: 10px;" type="tel" id="dashcommerce-reports-input-mobile-1" placeholder="Adicione um número">
    186                             <input style="margin-right: 10px;" type="tel" id="dashcommerce-reports-input-mobile-2" placeholder="Adicione um número">
    187                             <input type="tel" id="dashcommerce-reports-input-mobile-3" placeholder="Adicione um número">
    188                             (somente números, com código do país, DDD e dígito 9 - ex: 5561912345678)
     191                            <input style="margin-right: 10px;" type="tel" id="dashcommerce-reports-input-mobile-1">
     192                            <input style="margin-right: 10px;" type="tel" id="dashcommerce-reports-input-mobile-2">
     193                            <input type="tel" id="dashcommerce-reports-input-mobile-3">
    189194                        </div>
    190195                       
     
    419424        $topics  = $report_settings['topics'];
    420425
     426        $message = $this->generator->generate( 'daily', $store_name, $topics );
     427
    421428        if ( isset( $mobiles['mobile1'] ) && ! empty( $mobiles['mobile1'] ) ) {
    422             $message = $this->generator->generate( 'daily', $store_name, $topics );
    423 
    424429            $this->send_whatsapp_message( $mobiles['mobile1'], $message );
    425430        }
    426431
    427432        if ( isset( $mobiles['mobile2'] ) && ! empty( $mobiles['mobile2'] ) ) {
    428             $message = $this->generator->generate( 'daily', $store_name, $topics );
    429 
    430433            $this->send_whatsapp_message( $mobiles['mobile2'], $message );
    431434        }
    432435
    433436        if ( isset( $mobiles['mobile3'] ) && ! empty( $mobiles['mobile3'] ) ) {
    434             $message = $this->generator->generate( 'daily', $store_name, $topics );
    435 
    436437            $this->send_whatsapp_message( $mobiles['mobile3'], $message );
    437438        }
    438439
    439440        if ( isset( $webhook ) && ! empty( $webhook ) ) {
    440             $message = $this->generator->generate( 'daily', $store_name, $topics );
    441 
    442441            $this->send_webhook_call( $webhook, $message );
    443442        }
  • dashcommerce/trunk/features/reports/script-reports.js

    r3275268 r3286617  
    3333    constructor() {
    3434        this.elements.inputs.all.on('change input', async (event) => {
    35             this.toggleSave();
     35            this.toggleCanSaveOrSend();
    3636        });
    3737
     
    5050
    5151        dashcommerce_utils.finishLoading();
    52 
    5352    }
    5453
     
    6362            preferredTime: jQuery('#dashcommerce-reports-input-preferred-time'),
    6463            mobile1: jQuery('#dashcommerce-reports-input-mobile-1'),
     64            mobile1iti: null,
    6565            mobile2: jQuery('#dashcommerce-reports-input-mobile-2'),
     66            mobile2iti: null,
    6667            mobile3: jQuery('#dashcommerce-reports-input-mobile-3'),
     68            mobile3iti: null,
    6769            webhook: jQuery('#dashcommerce-reports-input-webhook'),
    6870            includeAccessCount: jQuery('#dashcommerce-reports-input-optional-accesses'),
     
    168170            },
    169171            mobiles: {
    170                 mobile1: this.elements.inputs.mobile1.val().toString() || null,
    171                 mobile2: this.elements.inputs.mobile2.val().toString() || null,
    172                 mobile3: this.elements.inputs.mobile3.val().toString() || null,
     172                mobile1: this.elements.inputs.mobile1iti.getNumber(window['intlTelInput'].utils.numberFormat.INTERNATIONAL)?.replace(/\D/g, '') || null,
     173                mobile2: this.elements.inputs.mobile2iti.getNumber(window['intlTelInput'].utils.numberFormat.INTERNATIONAL)?.replace(/\D/g, '') || null,
     174                mobile3: this.elements.inputs.mobile3iti.getNumber(window['intlTelInput'].utils.numberFormat.INTERNATIONAL)?.replace(/\D/g, '') || null,
    173175            },
    174176            time: dashcommerce_utils.hoursMinutesToGMT(this.elements.inputs.preferredTime.val()),
     
    205207     */
    206208    fill(settings) {
    207         if (!settings) return;
    208 
    209         this.savedSettings = settings;
    210 
    211         this.elements.inputs.dailyEnable.prop('checked', settings.schedules.daily.enable);
    212         this.elements.inputs.weeklyEnable.prop('checked', settings.schedules.weekly.enable);
    213         this.elements.inputs.monthlyEnable.prop('checked', settings.schedules.monthly.enable);
    214 
    215         this.elements.inputs.weeklyWeekday.val(settings.schedules.weekly.weekday);
    216 
    217         this.elements.inputs.preferredTime.val(dashcommerce_utils.hoursMinutesToLocal(settings.time));
    218 
    219         if (!settings.time) {
    220             this.elements.inputs.preferredTime.val('08:00');
    221         }
     209        this.elements.inputs.mobile1iti?.destroy();
     210        this.elements.inputs.mobile2iti?.destroy();
     211        this.elements.inputs.mobile3iti?.destroy();
    222212
    223213        this.elements.inputs.mobile1.val(settings.mobiles.mobile1);
     
    225215        this.elements.inputs.mobile3.val(settings.mobiles.mobile3);
    226216
    227         this.elements.inputs.webhook.val(settings.webhook);
    228 
    229         if (settings.topics) {
    230             this.elements.inputs.includeAccessCount.prop('checked', settings.topics.includes('access_count'));
    231             this.elements.inputs.includeSalesCount.prop('checked', settings.topics.includes('sales_count'));
    232             this.elements.inputs.includeIncome.prop('checked', settings.topics.includes('income'));
    233             this.elements.inputs.includeUtm.prop('checked', settings.topics.includes('utm'));
    234             this.elements.inputs.includeMostAccessedPages.prop('checked', settings.topics.includes('most_acessed_pages'));
    235             this.elements.inputs.includeMostViewedProds.prop('checked', settings.topics.includes('most_viewed_prods'));
    236             this.elements.inputs.includeMostSoldProducts.prop('checked', settings.topics.includes('most_sold_prods'));
    237         }
    238 
    239         this.elements.actions.save.attr('disabled', 'disabled');
    240 
    241         this.toggleSave();
     217        this.elements.inputs.mobile1iti = dashcommerce_utils.initializeItiField(
     218            this.elements.inputs.mobile1.get(0),
     219            dashcommerce_vars_reports?.country,
     220        );
     221
     222        this.elements.inputs.mobile2iti = dashcommerce_utils.initializeItiField(
     223            this.elements.inputs.mobile2.get(0),
     224            dashcommerce_vars_reports?.country,
     225        );
     226
     227        this.elements.inputs.mobile3iti = dashcommerce_utils.initializeItiField(
     228            this.elements.inputs.mobile3.get(0),
     229            dashcommerce_vars_reports?.country,
     230        );
     231
     232        this.savedSettings = settings;
     233
     234        this.elements.inputs.dailyEnable.prop('checked', settings?.schedules.daily.enable);
     235        this.elements.inputs.weeklyEnable.prop('checked', settings?.schedules.weekly.enable);
     236        this.elements.inputs.monthlyEnable.prop('checked', settings?.schedules.monthly.enable);
     237
     238        this.elements.inputs.weeklyWeekday.val(settings?.schedules.weekly.weekday);
     239
     240        this.elements.inputs.preferredTime.val(dashcommerce_utils.hoursMinutesToLocal(settings?.time));
     241
     242        if (!settings?.time) {
     243            this.elements.inputs.preferredTime.val('08:00');
     244        }
     245
     246        this.elements.inputs.webhook.val(settings?.webhook);
     247
     248        if (settings?.topics) {
     249            this.elements.inputs.includeAccessCount.prop('checked', settings?.topics.includes('access_count'));
     250            this.elements.inputs.includeSalesCount.prop('checked', settings?.topics.includes('sales_count'));
     251            this.elements.inputs.includeIncome.prop('checked', settings?.topics.includes('income'));
     252            this.elements.inputs.includeUtm.prop('checked', settings?.topics.includes('utm'));
     253            this.elements.inputs.includeMostAccessedPages.prop('checked', settings?.topics.includes('most_acessed_pages'));
     254            this.elements.inputs.includeMostViewedProds.prop('checked', settings?.topics.includes('most_viewed_prods'));
     255            this.elements.inputs.includeMostSoldProducts.prop('checked', settings?.topics.includes('most_sold_prods'));
     256        }
     257
     258        this.toggleCanSaveOrSend();
    242259    }
    243260
    244261    setSaving(isSaving) {
    245262        if (isSaving === true) {
     263            this.elements.actions.save.attr('disabled', 'disabled');
    246264            this.elements.spinners.saving.show();
    247265            this.elements.all.attr('disabled', 'disabled');
     
    250268            this.elements.spinners.saving.hide();
    251269            this.elements.all.removeAttr('disabled');
    252         }
    253 
    254         this.toggleSave();
    255 
    256         if (isSaving === true) {
    257             this.elements.actions.save.attr('disabled', 'disabled');
    258             this.elements.actions.send.attr('disabled', 'disabled');
    259         }
    260         else {
    261             this.elements.actions.send.removeAttr('disabled');
     270
     271            this.toggleCanSaveOrSend();
    262272        }
    263273    }
     
    265275    setSending(isSending) {
    266276        if (isSending === true) {
     277            this.elements.actions.send.attr('disabled', 'disabled');
    267278            this.elements.spinners.sending.show();
    268279            this.elements.all.attr('disabled', 'disabled');
    269             this.elements.actions.send.attr('disabled', 'disabled');
    270280        }
    271281        else {
    272282            this.elements.spinners.sending.hide();
    273283            this.elements.all.removeAttr('disabled');
    274             this.elements.actions.send.removeAttr('disabled');
    275         }
    276 
    277         this.toggleSave();
    278 
    279         if (isSending === true) {
    280             this.elements.actions.send.attr('disabled', 'disabled');
    281         }
    282         else {
    283             this.elements.actions.send.removeAttr('disabled');
    284         }
    285     }
    286 
    287     toggleSave() {
     284
     285            this.toggleCanSaveOrSend();
     286        }
     287    }
     288
     289    validateMobileNumbers() {
     290        const validateMobileNumber = (itiInput) => itiInput.isValidNumber() || itiInput.getNumber().length === 0;
     291
     292        const mobile1ok = validateMobileNumber(this.elements.inputs.mobile1iti);
     293        const mobile2ok = validateMobileNumber(this.elements.inputs.mobile2iti);
     294        const mobile3ok = validateMobileNumber(this.elements.inputs.mobile3iti);
     295
     296        return mobile1ok && mobile2ok && mobile3ok;
     297    }
     298
     299    toggleCanSaveOrSend() {
    288300        let dailyOk = true, weeklyOk = true, monthlyOk = true, mobilesOk = true;
    289301
    290302        const isTimeSelected = this.elements.inputs.preferredTime.val();
    291303        const isWeekdaySelected = this.elements.inputs.weeklyWeekday?.val() || null;
    292         const noMobileNumbers = !this.elements.inputs.mobile1.val() && !this.elements.inputs.mobile2.val() && !this.elements.inputs.mobile3.val();
    293304
    294305        if (this.elements.inputs.dailyEnable.prop('checked') && !isTimeSelected) {
     
    304315        }
    305316
    306         if (noMobileNumbers) {
     317        if (!this.validateMobileNumbers()) {
    307318            mobilesOk = false;
    308319        }
     
    310321        const settingsAreValid = dailyOk && weeklyOk && monthlyOk && mobilesOk;
    311322
    312         const okToSave = settingsAreValid && !dashcommerce_utils.deepEqual(this.savedSettings, this.getDisplayedSettings());
     323        const savedAndCurrentAreEqual = dashcommerce_utils.deepEqual(this.savedSettings, this.getDisplayedSettings());
     324
     325        const okToSave = settingsAreValid && !savedAndCurrentAreEqual;
    313326
    314327        if (okToSave) {
    315328            this.elements.actions.save.removeAttr('disabled');
    316             this.elements.actions.send.attr('disabled', 'disabled');
     329            console.log('can save', dailyOk, weeklyOk, monthlyOk, mobilesOk, settingsAreValid)
    317330        }
    318331        else {
    319332            this.elements.actions.save.attr('disabled', 'disabled');
     333            console.log('cannot save');
     334        }
     335
     336        const okToSend = savedAndCurrentAreEqual;
     337
     338        if (okToSend) {
    320339            this.elements.actions.send.removeAttr('disabled');
     340            console.log('can send');
     341        }
     342        else {
     343            this.elements.actions.send.attr('disabled', 'disabled');
     344            console.log('cannot send')
    321345        }
    322346    }
  • dashcommerce/trunk/readme.txt

    r3276913 r3286617  
    44Requires at least: WordPress 5.0
    55Tested up to: 6.8
    6 Stable tag: 1.3.3
     6Stable tag: 1.3.4
    77Requires PHP: 7.0.0
    88License: GPL v2
  • dashcommerce/trunk/utils/class-utils.php

    r3275268 r3286617  
    941941        return $admin_info;
    942942    }
     943
     944    /**
     945     * Get the site's country code based on the locale.
     946     *
     947     * @return string|null The country code in uppercase (e.g., 'BR', 'US', 'IT') or null if not set.
     948     */
     949    public function get_site_country() {
     950        $locale = get_option( 'WPLANG' );
     951
     952        if ( empty( $locale ) ) {
     953            return null;
     954        }
     955
     956        $locale_parts = explode( '_', $locale );
     957
     958        if ( ! isset( $locale_parts[1] ) ) {
     959            return null;
     960        }
     961
     962        return strtoupper( $locale_parts[1] );
     963    }
    943964}
    944965
  • dashcommerce/trunk/utils/script-utils.js

    r3275268 r3286617  
    177177
    178178    /**
    179      * Validates a Brazilian phone number.
    180      * 
    181      * @param {string} phone
    182      */
    183     validateBrPhone: (phone) => {
    184         phone = phone.replace(/\D/g, '');
    185 
    186         const regex = /^55(?:\d{2})[\s\-\(\)\.]*(?:9?\d{8})[\s\-\(\)\.]*$/;
    187 
    188         return regex.test(phone);
    189     },
    190 
    191     /**
    192179     * Downloads a base64 file via the user's browser.
    193180     *
     
    256243        a.click();
    257244        URL.revokeObjectURL(url);
    258     }
     245    },
     246
     247    /**
     248     * Initialize the International Telephone Input (ITI) field.
     249     * The intl-tel-input library must be included in the page (and present in `window`) for this to work.
     250     *
     251     * @param {HTMLElement} element - The input element to initialize.
     252     * @param {string | undefined} initialCountry - The initial country code. Defaults to `'US'`
     253     * @param {HTMLElement | undefined=} dependentButton - A button element that will be enabled/disabled based on the validity of the phone number.
     254     */
     255    initializeItiField: (element, initialCountry, dependentButton) => {
     256        const iti = window['intlTelInput'](element, {
     257            initialCountry: initialCountry || 'US',
     258            separateDialCode: true,
     259            showFlags: true,
     260            strictMode: true
     261        });
     262
     263        element.addEventListener('input', () => {
     264            if (iti.isValidNumber()) {
     265                element.style.borderColor = "unset";
     266
     267                dependentButton?.removeAttribute('disabled');
     268            }
     269            else {
     270                element.style.borderColor = "red";
     271
     272                dependentButton?.setAttribute('disabled', 'disabled');
     273            }
     274        });
     275
     276        return iti;
     277    },
    259278};
Note: See TracChangeset for help on using the changeset viewer.