🚸 (phone) Improve phone input behavior and validation
Now accepting landline phone numbers. Consistent select UI on every browser. Auto focus on country select.
This commit is contained in:
@ -37,7 +37,7 @@ test.describe('Phone input block', () => {
|
||||
|
||||
await page.click('text=Restart')
|
||||
await page.locator(`input[placeholder="+33 XX XX XX XX"]`).type('+33 6 73')
|
||||
await expect(page.getByRole('combobox')).toHaveText(/🇫🇷.+/)
|
||||
await expect(page.getByText('🇫🇷')).toBeVisible()
|
||||
await page.locator('button >> text="Go"').click()
|
||||
await expect(page.locator('text=Try again bro')).toBeVisible()
|
||||
await page
|
||||
|
@ -23,11 +23,11 @@
|
||||
"db": "workspace:*",
|
||||
"google-spreadsheet": "3.3.0",
|
||||
"got": "12.5.3",
|
||||
"libphonenumber-js": "^1.10.21",
|
||||
"next": "13.1.6",
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"nodemailer": "6.9.1",
|
||||
"openai": "^3.2.1",
|
||||
"phone": "^3.1.34",
|
||||
"qs": "6.11.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import phone from 'phone'
|
||||
import { parsePhoneNumber } from 'libphonenumber-js'
|
||||
|
||||
export const formatPhoneNumber = (phoneNumber: string) =>
|
||||
phone(phoneNumber).phoneNumber
|
||||
parsePhoneNumber(phoneNumber).formatInternational()
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { phone } from 'phone'
|
||||
import { isValidPhoneNumber } from 'libphonenumber-js'
|
||||
|
||||
export const validatePhoneNumber = (phoneNumber: string) =>
|
||||
phone(phoneNumber).isValid
|
||||
isValidPhoneNumber(phoneNumber)
|
||||
|
@ -50,13 +50,13 @@ export const continueBotFlow =
|
||||
message: 'Current block is not an input block',
|
||||
})
|
||||
|
||||
if (reply && !isReplyValid(reply, block)) return parseRetryMessage(block)
|
||||
|
||||
const formattedReply = formatReply(reply, block.type)
|
||||
|
||||
if (!formattedReply && !canSkip(block.type)) {
|
||||
return parseRetryMessage(block)
|
||||
}
|
||||
if (formattedReply && !isReplyValid(formattedReply, block))
|
||||
return parseRetryMessage(block)
|
||||
|
||||
const newSessionState = await processAndSaveAnswer(
|
||||
state,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/js",
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.22",
|
||||
"description": "Javascript library to display typebots on your website",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
16
packages/js/src/components/icons/ChevronDownIcon.tsx
Normal file
16
packages/js/src/components/icons/ChevronDownIcon.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { JSX } from 'solid-js/jsx-runtime'
|
||||
|
||||
export const ChevronDownIcon = (props: JSX.SvgSVGAttributes<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2px"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9" />
|
||||
</svg>
|
||||
)
|
@ -1,4 +1,5 @@
|
||||
import { ShortTextInput } from '@/components'
|
||||
import { ChevronDownIcon } from '@/components/icons/ChevronDownIcon'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
@ -75,7 +76,13 @@ export const PhoneInput = (props: PhoneInputProps) => {
|
||||
const selectNewCountryCode = (
|
||||
event: Event & { currentTarget: { value: string } }
|
||||
) => {
|
||||
setSelectedCountryCode(event.currentTarget.value)
|
||||
const code = event.currentTarget.value
|
||||
setSelectedCountryCode(code)
|
||||
const dial_code = phoneCountries.find(
|
||||
(country) => country.code === code
|
||||
)?.dial_code
|
||||
if (inputValue() === '' && dial_code) setInputValue(dial_code)
|
||||
inputRef?.focus()
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@ -91,30 +98,37 @@ export const PhoneInput = (props: PhoneInputProps) => {
|
||||
}}
|
||||
onKeyDown={submitWhenEnter}
|
||||
>
|
||||
<div class="flex flex-1">
|
||||
<select
|
||||
onChange={selectNewCountryCode}
|
||||
class="w-12 pl-2 focus:outline-none rounded-lg typebot-country-select"
|
||||
>
|
||||
<option selected>
|
||||
{
|
||||
phoneCountries.find(
|
||||
(country) => selectedCountryCode() === country.code
|
||||
)?.flag
|
||||
}
|
||||
</option>
|
||||
<For
|
||||
each={phoneCountries.filter(
|
||||
(country) => country.code !== selectedCountryCode()
|
||||
)}
|
||||
<div class="flex">
|
||||
<div class="relative typebot-country-select flex justify-center items-center rounded-md">
|
||||
<div class="pl-2 pr-1 flex items-center gap-2">
|
||||
<span>
|
||||
{
|
||||
phoneCountries.find(
|
||||
(country) => selectedCountryCode() === country.code
|
||||
)?.flag
|
||||
}
|
||||
</span>
|
||||
<ChevronDownIcon class="w-3" />
|
||||
</div>
|
||||
|
||||
<select
|
||||
onChange={selectNewCountryCode}
|
||||
class="absolute top-0 left-0 w-full h-full cursor-pointer opacity-0"
|
||||
>
|
||||
{(country) => (
|
||||
<option value={country.code}>
|
||||
{country.name} ({country.dial_code})
|
||||
</option>
|
||||
)}
|
||||
</For>
|
||||
</select>
|
||||
<For each={phoneCountries}>
|
||||
{(country) => (
|
||||
<option
|
||||
value={country.code}
|
||||
selected={country.code === selectedCountryCode()}
|
||||
>
|
||||
{country.name}{' '}
|
||||
{country.dial_code ? `(${country.dial_code})` : ''}
|
||||
</option>
|
||||
)}
|
||||
</For>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<ShortTextInput
|
||||
type="tel"
|
||||
ref={inputRef}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/react",
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.22",
|
||||
"description": "React library to display typebots on your website",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
@ -370,6 +370,7 @@ importers:
|
||||
google-auth-library: 8.7.0
|
||||
google-spreadsheet: 3.3.0
|
||||
got: 12.5.3
|
||||
libphonenumber-js: ^1.10.21
|
||||
models: workspace:*
|
||||
next: 13.1.6
|
||||
next-transpile-modules: 10.0.0
|
||||
@ -378,7 +379,6 @@ importers:
|
||||
nodemailer: 6.9.1
|
||||
openai: ^3.2.1
|
||||
papaparse: 5.3.2
|
||||
phone: ^3.1.34
|
||||
qs: 6.11.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
@ -400,11 +400,11 @@ importers:
|
||||
db: link:../../packages/db
|
||||
google-spreadsheet: 3.3.0
|
||||
got: 12.5.3
|
||||
libphonenumber-js: 1.10.21
|
||||
next: 13.1.6_6m24vuloj5ihw4zc5lbsktc4fu
|
||||
nextjs-cors: 2.1.2_next@13.1.6
|
||||
nodemailer: 6.9.1
|
||||
openai: 3.2.1
|
||||
phone: 3.1.34
|
||||
qs: 6.11.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
@ -14284,6 +14284,10 @@ packages:
|
||||
resolution: {integrity: sha512-MDZ1zLIkfSDZV5xBta3nuvbEOlsnKCPe4z5r3hyup/AXveevkl9A1eSWmLhd2FX4k7pJDe4MrLeQsux0HI/VWg==}
|
||||
dev: false
|
||||
|
||||
/libphonenumber-js/1.10.21:
|
||||
resolution: {integrity: sha512-/udZhx49av2r2gZR/+xXSrwcR8smX/sDNrVpOFrvW+CA26TfYTVZfwb3MIDvmwAYMLs7pXuJjZX0VxxGpqPhsA==}
|
||||
dev: false
|
||||
|
||||
/lie/3.1.1:
|
||||
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
|
||||
dependencies:
|
||||
@ -15983,11 +15987,6 @@ packages:
|
||||
sha.js: 2.4.11
|
||||
dev: false
|
||||
|
||||
/phone/3.1.34:
|
||||
resolution: {integrity: sha512-h+nJqLyzA4vbPlD9poMS6fqeW4Dz1lRNPK9qHmrM7Pqkac/0RdiFZrbSJTVxE5xj/HFAaggQTZyfj6XmSjootA==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/php-parser/3.1.3:
|
||||
resolution: {integrity: sha512-hPvBmnRYPqWEtMfIFOlyjQv1q75UUtxt4U+YscKIQViGmEE2Xa4BuS1B1/cZdjy7MVcwtnr0WkEsr915LgRKOw==}
|
||||
dev: true
|
||||
|
Reference in New Issue
Block a user