create_form #48
|
|
@ -55,7 +55,7 @@ const fetchConfig = async () => {
|
||||||
formData[field.key] = [];
|
formData[field.key] = [];
|
||||||
} else if (field.type === "phone_country") {
|
} else if (field.type === "phone_country") {
|
||||||
formData[field.key] = "";
|
formData[field.key] = "";
|
||||||
phoneParts[field.key] = { code: "", number: "" };
|
phoneParts[field.key] = { code: "", number: "", flag: "" };
|
||||||
} else {
|
} else {
|
||||||
formData[field.key] = "";
|
formData[field.key] = "";
|
||||||
}
|
}
|
||||||
|
|
@ -305,13 +305,6 @@ const onPhoneInput = (key, event) => {
|
||||||
formatErrors[key] = false;
|
formatErrors[key] = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPhoneCountryCodeChange = (key, code) => {
|
|
||||||
if (!phoneParts[key]) return;
|
|
||||||
phoneParts[key].code = code;
|
|
||||||
formData[key] = code + phoneParts[key].number;
|
|
||||||
stepErrors[key] = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPhoneCountryNumberInput = (key, event) => {
|
const onPhoneCountryNumberInput = (key, event) => {
|
||||||
if (!phoneParts[key]) return;
|
if (!phoneParts[key]) return;
|
||||||
const cleaned = event.target.value.replace(/\D/g, "");
|
const cleaned = event.target.value.replace(/\D/g, "");
|
||||||
|
|
@ -321,8 +314,56 @@ const onPhoneCountryNumberInput = (key, event) => {
|
||||||
stepErrors[key] = false;
|
stepErrors[key] = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPhoneCountryDisplay = (key) => {
|
||||||
|
if (phoneCountrySearchText[key] !== undefined && phoneCountrySearchText[key] !== null) {
|
||||||
|
return phoneCountrySearchText[key];
|
||||||
|
}
|
||||||
|
if (!phoneParts[key] || !phoneParts[key].code) return "";
|
||||||
|
return phoneParts[key].flag
|
||||||
|
? `${phoneParts[key].code}`
|
||||||
|
: phoneParts[key].code;
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredPhoneCountries = (field, key) => {
|
||||||
|
const text = (phoneCountrySearchText[key] || "").toLowerCase().trim();
|
||||||
|
const list = suggestionsCache.value[field.source] || [];
|
||||||
|
if (!text) return list;
|
||||||
|
return list.filter(
|
||||||
|
item => item.label.toLowerCase().includes(text) || item.dial_code.includes(text)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPhoneCountrySearchFocus = (field, key) => {
|
||||||
|
loadSuggestions(field.source);
|
||||||
|
showCountrySuggestions[key] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPhoneCountrySearchBlur = (key) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
showCountrySuggestions[key] = false;
|
||||||
|
phoneCountrySearchText[key] = undefined;
|
||||||
|
}, 200);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPhoneCountrySearchInput = (key, event) => {
|
||||||
|
phoneCountrySearchText[key] = event.target.value;
|
||||||
|
showCountrySuggestions[key] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPhoneCountrySelect = (key, item) => {
|
||||||
|
phoneParts[key].code = item.dial_code;
|
||||||
|
phoneParts[key].flag = item.flag;
|
||||||
|
phoneParts[key].number = phoneParts[key].number || "";
|
||||||
|
formData[key] = item.dial_code + phoneParts[key].number;
|
||||||
|
phoneCountrySearchText[key] = undefined;
|
||||||
|
showCountrySuggestions[key] = false;
|
||||||
|
stepErrors[key] = false;
|
||||||
|
};
|
||||||
|
|
||||||
const suggestionsCache = ref({});
|
const suggestionsCache = ref({});
|
||||||
const showSuggestions = reactive({});
|
const showSuggestions = reactive({});
|
||||||
|
const phoneCountrySearchText = reactive({});
|
||||||
|
const showCountrySuggestions = reactive({});
|
||||||
|
|
||||||
const loadSuggestions = async (source) => {
|
const loadSuggestions = async (source) => {
|
||||||
if (suggestionsCache.value[source]) return;
|
if (suggestionsCache.value[source]) return;
|
||||||
|
|
@ -583,18 +624,39 @@ const getFieldInputType = (field) => {
|
||||||
|
|
||||||
<div v-else-if="field.type === 'phone_country'" class="relative">
|
<div v-else-if="field.type === 'phone_country'" class="relative">
|
||||||
<div class="join w-full">
|
<div class="join w-full">
|
||||||
<select
|
<div class="join-item relative w-28">
|
||||||
class="select join-item bg-white border-gray-200 w-[8.5rem] rounded-l-xl text-sm focus:outline-2 focus:outline-[#22523F] grow text-[#1a1a1a]"
|
|
||||||
:class="{ 'border-red-500': getFieldError(field.key) }"
|
|
||||||
@change="onPhoneCountryCodeChange(field.key, $event.target.value)"
|
|
||||||
>
|
|
||||||
<option value="" selected disabled>{{ tl("form.phone_code_select") }}</option>
|
|
||||||
<option v-for="item in getSelectOptions(field)" :key="item.value" :value="item.dial_code">
|
|
||||||
{{ item.flag }} {{ item.dial_code }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<label
|
<label
|
||||||
class="input join-item rounded-r-xl grow bg-white border-gray-200 focus-within:outline-2 focus-within:outline-[#22523F]"
|
class="input border-gray-200 rounded-l-xl bg-white w-full focus-within:outline-2 focus-within:outline-[#22523F]"
|
||||||
|
:class="{ 'border-red-500': getFieldError(field.key) }"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="w-full text-[#1a1a1a]"
|
||||||
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
|
:value="getPhoneCountryDisplay(field.key)"
|
||||||
|
:placeholder="tl('form.phone_code_select')"
|
||||||
|
@input="onPhoneCountrySearchInput(field.key, $event)"
|
||||||
|
@focus="onPhoneCountrySearchFocus(field, field.key)"
|
||||||
|
@blur="onPhoneCountrySearchBlur(field.key)"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ul
|
||||||
|
v-if="showCountrySuggestions[field.key] && filteredPhoneCountries(field, field.key).length"
|
||||||
|
class="absolute left-0 right-0 z-50 bg-white shadow-lg rounded-b-xl border border-gray-200 border-t-0 max-h-[200px] overflow-y-auto"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="item in filteredPhoneCountries(field, field.key)"
|
||||||
|
:key="item.value"
|
||||||
|
class="px-3 py-2 cursor-pointer text-sm text-[#1a1a1a] hover:bg-[#22523F]/10 transition-colors flex items-center gap-2"
|
||||||
|
@mousedown.prevent="onPhoneCountrySelect(field.key, item)"
|
||||||
|
>
|
||||||
|
<span>{{ item.flag }}</span>
|
||||||
|
<span class="font-mono">{{ item.dial_code }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<label
|
||||||
|
class="input join-item grow bg-white rounded-r-xl border-gray-200 focus-within:outline-2 focus-within:outline-[#22523F]"
|
||||||
:class="{ 'border-red-500': getFieldError(field.key) }"
|
:class="{ 'border-red-500': getFieldError(field.key) }"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue