hybridinteractive / craft-contact-form-extensions

Adds extensions to the Craft CMS contact form plugin.
MIT License
43 stars 36 forks source link

Admin Panel - Form Submissions view issue: Argument 1 passed to craft\helpers\StringHelper::convertToUtf8() #147

Closed joelod closed 2 years ago

joelod commented 2 years ago

Hi,

I'm having an issue while consulting the Form Submissions on the admin panel. For a specific site, everytime I click on the submission ID, I get the following error:

Argument 1 passed to craft\helpers\StringHelper::convertToUtf8() must be of the type string, object given, called in /var/www/vhosts/costanovaprofessional.pt/costanovaprofessional.pt/vendor/hybridinteractive/craft-contact-form-extensions/src/services/ContactFormExtensionsService.php on line 131

Have anyone faced this issue before? I believe the issue is the way I'm building up the form data, but I'm not sure how can I end up solving this.

rosskenney commented 2 years ago

@joelod If you could export the raw data from the submissions it might help pinpoint which data it is having trouble with and how we can fix this. If it's test data feel free to drop it here.

image
joelod commented 2 years ago

@rosskenney thank you, yes I've attached an example of the exported data. elements.csv

rosskenney commented 2 years ago

@joelod I think it might be the product doing it. Can you send me the front end form code. I just need the form itself and you can send the html version if you are using craft to populate the products etc. I want to run a few test scenarios to see what the root cause is.

rosskenney commented 2 years ago

@joelod are you saving this using js? Do you have an example on a demo or live site?

joelod commented 2 years ago

@rosskenney sorry I forgot my answer the other day. Yes I'm using JS with jQuery, here's my code for the Ajax submission:


$form.submit( function(e){
        e.preventDefault()
        let formData = new FormData($form[0]),
            formDataArray =  $form.serializeArray();

        // Contact Form Plugin data
        formData.append('fromEmail', $.trim($form.find('[name="message[Email]"]').val()));
        formData.append('action', 'contact-form/send');

        const country = $.trim($form.find('[name="message[Country]"]').val());

        if (country === 'United States') {
          const toEmailUSA = $.trim($form.find('[name="toEmailUSA"]').val());
          formData.append('toEmail', toEmailUSA);
        } else if (country === 'Portugal' || country === 'Spain') {
          const toEmailIb = $.trim($form.find('[name="toEmailIb"]').val());
          formData.append('toEmail', toEmailIb);
        } else {
          const toEmailRoW = $.trim($form.find('[name="toEmailRoW"]').val());
          formData.append('toEmail', toEmailRoW);
        }

        const $wishlistItem = $(wishlist.elements.wishlistPage.item);

        $wishlistItem.each(function(){
          const item = this,
                sku = $(item).attr('data-product-sku'),
                quantity = $(wishlist.elements.wishlistPage.quantity+'[data-product-sku="'+sku+'"]').val();

          formData.append('message[products]['+sku+']', quantity);

        });

        $.ajax({
          contentType: false,
          processData: false,
          method: "POST",
          url: self.strings.submitUrl+'/',
          dataType: "json",
          data: formData,
          beforeSend: function() {
            $formContainer.addClass(defaults.status.loading);
            $fieldset.prop('disabled', true);
          },
        }).always(function() {
          $formContainer.removeClass(defaults.status.loading);
          $fieldset.prop('disabled', false);
        }).done(function(data) {
          if(data.success == true){
            $form[0].reset();
            $.notify(self.strings.messageSuccess,{
              style: 'cnp',
            });
          }else{
            var allErrors = Array();
            for ( fieldErrors of Object.values(data.errors)){
              var concatedArray =  allErrors.concat(fieldErrors);
              allErrors = concatedArray;
            }
            var errorString = allErrors.join(' ');
            alert(errorString);
            $.notify(errorString,{
              style: 'cnp',
            });
          }
        }).fail(function(data) {
          $.notify(self.strings.messageFail,{
            style: 'cnp',
          });
        });
      })
joelod commented 2 years ago

And here's the HTML for the form:

        <form class="form h-contact-form">
          {{ csrfInput() }}

          <input type="hidden" name="toEmailIb" value="{{ 'ib@costanova.pt'|hash }}">
          <input type="hidden" name="toEmailUSA" value="{{ 'julia@casafinagifts.com'|hash }}">
          <input type="hidden" name="toEmailRoW" value="{{ 'info@costanova.pt'|hash }}">

          <formset class="cells cells-gutter-20 cells-spacer-20 h-contact-form-fieldset">

            <div class="cell cell-12 md--cell-6">
              <label for="first-name" class="form-label">{{ 'Name'|t }} *</label>
              <input name="message[First name]" id="first-name" type="text" required>
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="last-name" class="form-label">{{ 'Last name'|t }} *</label>
              <input name="message[Last name]" id="last-name" type="text" required>
            </div>

            <div class="cell cell-12 md--cell-8">
              <label for="email" class="form-label">{{ 'Email'|t }} *</label>
              <input name="message[Email]" id="email" type="email" required>
            </div>

            <div class="cell cell-12 md--cell-4">
              <label for="phone-number" class="form-label">{{ 'Phone number'|t }} *</label>
              <input name="message[Phone number]" id="phone-number" type="text" required>
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="company-name" class="form-label">{{ 'Company name'|t }} *</label>
              <input name="message[Company name]" id="company-name" type="text" required>
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="website" class="form-label">{{ 'Website'|t }}</label>
              <input name="message[Website]" id="website" type="text">
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="company-type" class="form-label">{{ 'Company type'|t }} *</label>
              <select name="message[Company type]" id="company-type" required>
                <option value="">-</option>
                <option value="Catering">Catering</option>
                <option value="Chefs">Chefs</option>
                <option value="Distributor">Distributor</option>
                <option value="Hotels">Hotels</option>
                <option value="Restaurants / Cafés">Restaurants / Cafés</option>
              </select>
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="job-title" class="form-label">{{ 'Job title'|t }}</label>
              <input name="message[Job title]" id="job-title" type="text">
            </div>

            <div class="cell cell-12 md--cell-8">
              <label for="address" class="form-label">{{ 'Address'|t }}</label>
              <input name="message[Address]" id="address" type="text">
            </div>

            <div class="cell cell-12 md--cell-4">
              <label for="zip-code" class="form-label">{{ 'Zip Code'|t }}</label>
              <input name="message[Zip code]" id="zip-code" type="text">
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="city" class="form-label">{{ 'City/State'|t }} *</label>
              <input name="message[City]" id="city" type="text" required>
            </div>

            <div class="cell cell-12 md--cell-6">
              <label for="country" class="form-label">{{ 'Country'|t }} *</label>
              <select name="message[Country]" id="country" required>
                <option value="">-</option>
                <option value="Afghanistan">Afghanistan</option>
              (...)
                <option value="Yemen">Yemen</option>
                <option value="Zambia">Zambia</option>
                <option value="Zimbabwe">Zimbabwe</option>
              </select>
            </div>

            <div class="cell cell-12">
              <label for="description" class="form-label">{{ 'Description'|t }}</label>
              <textarea name="message[Description]" id="description" rows="4"></textarea>
            </div>
          </formset>

          <div class="cells cells-apart padding-top-30">
            <div class="cell">
              {% include 'partials/button' with {
                data: {
                  label: 'Continue my selection'|t,
                  url: mainNav.collections.url,
                },
                classnames: {
                  root: 'button--reverse'
                },
                settings: {
                  style: 'arrow',
                }
              } %}
            </div>

            <div class="cell">
              <button class="h-contact-form-send">
                {% include 'partials/button' with {
                  data: {
                    label: 'Send quote request'|t,
                  },
                  settings: {
                    style: 'arrow',
                    nonLink: true,
                  }
                } %}
              </button>
            </div>
          </div>

          <div class="padding-top-30 t-right">
            <p class="t-size-12">* {{ 'This is a required field.'|t }}</p>
          </div>
        </form>`
rosskenney commented 2 years ago

@joelod Thank you! I will take a look at this to see what I can do.

joelod commented 2 years ago

@rosskenney thank you!

rosskenney commented 2 years ago

Setting this up and running it locally, I see it is for sure the object being created. This plugin follows what is allowed from the Craft Contact Form, hence why it doesn't know how to output it. I would take a look at https://github.com/craftcms/contact-form to keep in line with what the plugin can handle. This plugin is just an extension of that one.

joelod commented 2 years ago

@rosskenney makes sense to me, thanks I'll do that.