Phone input prefill country issue fixed (#213)

* fix prefill phone issue

* js phone parse fixes

* revert last change

* fix phone UI

* Code optimize

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
formsdev 2023-10-03 21:20:46 +05:30 committed by GitHub
parent 54f92f844f
commit f7ecd6f233
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 310 additions and 38 deletions

View File

@ -220,14 +220,14 @@ class AnswerFormRequest extends FormRequest
protected function prepareForValidation()
{
// Escape all '\' in select options
$receivedData = $this->toArray();
$mergeData = [];
collect($this->form->properties)->filter(function ($property) {
return in_array($property['type'], ['select', 'multi_select']);
})->each(function ($property) use ($receivedData, &$mergeData) {
$countryCodeMapper = json_decode(file_get_contents(resource_path('data/country_code_mapper.json')), true);
collect($this->form->properties)->each(function ($property) use ($countryCodeMapper, $receivedData, &$mergeData) {
$receivedValue = $receivedData[$property['id']] ?? null;
if (!is_null($receivedValue)) {
// Escape all '\' in select options
if(in_array($property['type'], ['select', 'multi_select']) && !is_null($receivedValue)){
if (is_array($receivedValue)) {
$mergeData[$property['id']] = collect($receivedValue)->map(function ($value) {
$value = Str::of($value);
@ -244,6 +244,10 @@ class AnswerFormRequest extends FormRequest
)->toString();
}
}
if($property['type'] === 'phone_number' && (!isset($property['use_simple_text_input']) || !$property['use_simple_text_input']) && $receivedValue && in_array($receivedValue, $countryCodeMapper)){
$mergeData[$property['id']] = null;
}
});
$this->merge($mergeData);

View File

@ -131,6 +131,11 @@ class StoreFormSubmissionJob implements ShouldQueue
if($this->form->is_pro && $field['type'] == 'signature') {
$finalData[$field['id']] = $this->storeSignature($answerValue);
}
// For Phone
if($field['type'] == 'phone_number' && $answerValue && ctype_alpha(substr($answerValue, 0, 2)) && (!isset($field['use_simple_text_input']) || !$field['use_simple_text_input'])) {
$finalData[$field['id']] = substr($answerValue, 2);
}
}
return $finalData;

View File

@ -12,10 +12,13 @@ class ValidPhoneInputRule implements Rule
public function passes($attribute, $value)
{
if (!is_string($value) || !Str::startsWith($value, '+')) {
if (!is_string($value) || !$value) {
return false;
}
try {
if(ctype_alpha(substr($value, 0, 2))){ // First 2 will be country code
$value = substr($value, 2);
}
$phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();
$phone = $phoneUtil->parse($value);
$this->reason = $phoneUtil->isPossibleNumberWithReason($phone);

View File

@ -0,0 +1,248 @@
[
"AF+93",
"AX+358",
"AL+355",
"DZ+213",
"AS+1684",
"AD+376",
"AO+244",
"AI+1264",
"AQ+672",
"AG+1268",
"AR+54",
"AM+374",
"AW+297",
"AU+61",
"AT+43",
"AZ+994",
"BS+1242",
"BH+973",
"BD+880",
"BB+1246",
"BY+375",
"BE+32",
"BZ+501",
"BJ+229",
"BM+1441",
"BT+975",
"BO+591",
"BA+387",
"BW+267",
"BV+47",
"BR+55",
"IO+246",
"BN+673",
"BG+359",
"BF+226",
"BI+257",
"KH+855",
"CM+237",
"CA+1",
"CV+238",
"KY+345",
"CF+236",
"TD+235",
"CL+56",
"CN+86",
"CX+61",
"CC+61",
"CO+57",
"KM+269",
"CG+242",
"CD+243",
"CK+682",
"CR+506",
"CI+225",
"HR+385",
"CU+53",
"CY+357",
"CZ+420",
"DK+45",
"DJ+253",
"DM+1767",
"DO+1849",
"EC+593",
"EG+20",
"SV+503",
"GQ+240",
"ER+291",
"EE+372",
"ET+251",
"FK+500",
"FO+298",
"FJ+679",
"FI+358",
"FR+33",
"GF+594",
"PF+689",
"TF+262",
"GA+241",
"GM+220",
"GE+995",
"DE+49",
"GH+233",
"GI+350",
"GR+30",
"GL+299",
"GD+1473",
"GP+590",
"GU+1671",
"GT+502",
"GG+44",
"GN+224",
"GW+245",
"GY+592",
"HT+509",
"HM+672",
"VA+379",
"HN+504",
"HK+852",
"HU+36",
"IS+354",
"IN+91",
"ID+62",
"IR+98",
"IQ+964",
"IE+353",
"IM+44",
"IL+972",
"IT+39",
"JM+1876",
"JP+81",
"JE+44",
"JO+962",
"KZ+7",
"KE+254",
"KI+686",
"KP+850",
"KR+82",
"XK+383",
"KW+965",
"KG+996",
"LA+856",
"LV+371",
"LB+961",
"LS+266",
"LR+231",
"LY+218",
"LI+423",
"LT+370",
"LU+352",
"MO+853",
"MK+389",
"MG+261",
"MW+265",
"MY+60",
"MV+960",
"ML+223",
"MT+356",
"MH+692",
"MQ+596",
"MR+222",
"MU+230",
"YT+262",
"MX+52",
"FM+691",
"MD+373",
"MC+377",
"MN+976",
"ME+382",
"MS+1664",
"MA+212",
"MZ+258",
"MM+95",
"NA+264",
"NR+674",
"NP+977",
"NL+31",
"AN+599",
"NC+687",
"NZ+64",
"NI+505",
"NE+227",
"NG+234",
"NU+683",
"NF+672",
"MP+1670",
"NO+47",
"OM+968",
"PK+92",
"PW+680",
"PS+970",
"PA+507",
"PG+675",
"PY+595",
"PE+51",
"PH+63",
"PN+64",
"PL+48",
"PT+351",
"PR+1939",
"QA+974",
"RO+40",
"RU+7",
"RW+250",
"RE+262",
"BL+590",
"SH+290",
"KN+1869",
"LC+1758",
"MF+590",
"PM+508",
"VC+1784",
"WS+685",
"SM+378",
"ST+239",
"SA+966",
"SN+221",
"RS+381",
"SC+248",
"SL+232",
"SG+65",
"SK+421",
"SI+386",
"SB+677",
"SO+252",
"ZA+27",
"SS+211",
"GS+500",
"ES+34",
"LK+94",
"SD+249",
"SR+597",
"SJ+47",
"SZ+268",
"SE+46",
"CH+41",
"SY+963",
"TW+886",
"TJ+992",
"TZ+255",
"TH+66",
"TL+670",
"TG+228",
"TK+690",
"TO+676",
"TT+1868",
"TN+216",
"TR+90",
"TM+993",
"TC+1649",
"TV+688",
"UG+256",
"UA+380",
"AE+971",
"GB+44",
"US+1",
"UY+598",
"UZ+998",
"VU+678",
"VE+58",
"VN+84",
"VG+1284",
"VI+1340",
"WF+681",
"YE+967",
"ZM+260",
"ZW+263"
]

View File

@ -13,7 +13,7 @@
</small>
</div>
<div :id="id ? id : name" :name="name" :style="inputStyle" class="flex items-center">
<v-select class="w-[110px]" dropdown-class="w-[350px]" input-class="rounded-r-none" :data="countries"
<v-select class="w-[130px]" dropdown-class="w-[300px]" input-class="rounded-r-none" :data="countries"
v-model="selectedCountryCode"
:has-error="hasValidation && form.errors.has(name)"
:disabled="disabled" :searchable="true" :search-keys="['name']" :option-key="'code'" :color="color"
@ -54,64 +54,74 @@ import parsePhoneNumber from 'libphonenumber-js'
export default {
phone: 'PhoneInput',
components: {CountryFlag},
components: { CountryFlag },
directives: {
onClickaway: onClickaway
},
mixins: [inputMixin],
props: {
canOnlyCountry: {type: Boolean, default: false}
canOnlyCountry: { type: Boolean, default: false }
},
data() {
data () {
return {
selectedCountryCode: this.getCountryBy('US'), // Default US
selectedCountryCode: null,
countries: countryCodes,
inputVal: null
}
},
mounted() {
if (this.compVal) {
const phoneObj = parsePhoneNumber(this.compVal)
if (phoneObj !== undefined && phoneObj) {
if (phoneObj.country !== undefined && phoneObj.country) {
this.selectedCountryCode = this.getCountryBy(phoneObj.country)
watch: {
inputVal: {
handler (val) {
if (val && val.startsWith('0')) {
val = val.substring(1)
}
this.inputVal = phoneObj.nationalNumber
} else if (this.compVal) {
this.selectedCountryCode = this.getCountryBy(this.compVal, 'dial_code')
if (this.canOnlyCountry) {
this.compVal = (val) ? this.selectedCountryCode.code + this.selectedCountryCode.dial_code + val : this.selectedCountryCode.code + this.selectedCountryCode.dial_code
} else {
this.compVal = (val) ? this.selectedCountryCode.code + this.selectedCountryCode.dial_code + val : null
}
}
},
selectedCountryCode (newVal, oldVal) {
if (this.compVal && newVal && oldVal) {
this.compVal = this.compVal.replace(oldVal.code + oldVal.dial_code, newVal.code + newVal.dial_code)
}
}
},
watch: {
inputVal: {
handler(val) {
if (val && val.startsWith('0')) {
val = val.substring(1)
}
this.compVal = (val) ? this.selectedCountryCode.dial_code + val : null
}
},
selectedCountryCode(newVal, oldVal) {
mounted () {
if (this.compVal) {
this.compVal = this.compVal.replace(oldVal.dial_code, newVal.dial_code)
if(!this.compVal.startsWith('+')){
this.selectedCountryCode = this.getCountryBy(this.compVal.substring(2, 0))
}
const phoneObj = parsePhoneNumber(this.compVal)
if (phoneObj !== undefined && phoneObj) {
if (!this.selectedCountryCode && phoneObj.country !== undefined && phoneObj.country) {
this.selectedCountryCode = this.getCountryBy(phoneObj.country)
}
this.inputVal = phoneObj.nationalNumber
}
}
if(!this.selectedCountryCode){
this.selectedCountryCode = this.getCountryBy()
}
},
methods: {
getCountryBy(code, type = 'code') {
getCountryBy (code = 'US', type = 'code') {
if(!code) code = 'US' // Default US
return countryCodes.find((item) => {
return item[type] === code
})
},
onInput(event) {
onInput (event) {
this.inputVal = event.target.value.replace(/[^0-9]/g, '')
},
onChangeCountryCode() {
onChangeCountryCode () {
if (this.canOnlyCountry && (this.inputVal === null || this.inputVal === '' || !this.inputVal)) {
this.compVal = this.selectedCountryCode.dial_code
this.compVal = this.selectedCountryCode.code + this.selectedCountryCode.dial_code
}
}
}

View File

@ -59,7 +59,8 @@
</div>
<template v-if="filteredOptions.length>0">
<li v-for="item in filteredOptions" :key="item[optionKey]" role="option" :style="optionStyle"
class="text-gray-900 cursor-default select-none relative py-2 pl-3 pr-9 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus:text-white focus:bg-nt-blue"
:class="{'px-3 pr-9':multiple, 'px-3':!multiple}"
class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus:text-white focus:bg-nt-blue"
:dusk="dusk+'_option'" @click="select(item)"
>
<slot name="option" :option="item" :selected="isSelected(item)" />
@ -69,7 +70,8 @@
{{ (allowCreation ? 'Type something to add an option': 'No option available') }}.
</p>
<li v-if="allowCreation && searchTerm" role="option" :style="optionStyle"
class="text-gray-900 cursor-default select-none relative py-2 pl-3 pr-9 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus:text-white focus:bg-nt-blue"
:class="{'px-3 pr-9':multiple, 'px-3':!multiple}"
class="text-gray-900 cursor-default select-none relative py-2 cursor-pointer group hover:text-white hover:bg-form-color focus:outline-none focus:text-white focus:bg-nt-blue"
@click="createOption(searchTerm)"
>
Create <b class="px-1 bg-gray-300 rounded group-hover:text-black">{{ searchTerm }}</b>

View File

@ -44,7 +44,7 @@ class FormSubmissionDataFactory
$value = $this->faker->url();
break;
case 'phone_number':
$value = '+33749119783';
$value = 'FR+33749119783';
break;
case 'date':
$value = $this->faker->date();