UNPKG

@blocklet/payment-react

Version:

Reusable react components for payment kit v2

110 lines (86 loc) 5.32 kB
# PhoneInput The `PhoneInput` component provides a user-friendly, international phone number input field. It integrates seamlessly with `react-hook-form` and includes a searchable country selector with flags and dial codes, automatic number formatting, and powerful validation powered by `google-libphonenumber`. This component is designed to work in tandem with other form elements, such as the [`CountrySelect`](./components-ui-form-elements-country-select.md) or [`AddressForm`](./components-ui-form-elements-address-form.md), by synchronizing its selected country with a shared form field. ## How It Works The component leverages the `react-international-phone` library for its core functionality and wraps it to provide deep integration with `react-hook-form` and Material-UI. When a user selects a country or types a number, the component updates the corresponding fields in the form state. It also automatically updates its country selection when another component modifies the linked country field in the form. <!-- DIAGRAM_IMAGE_START:architecture:16:9 --> ![PhoneInput](assets/diagram/phone-input-diagram-0.jpg) <!-- DIAGRAM_IMAGE_END --> ## Props The `PhoneInput` component accepts all standard Material-UI `TextField` props, in addition to the following specific props: | Prop | Type | Required | Default | Description | |---|---|---|---|---| | `name` | `string` | Yes | - | The name of the field to register with `react-hook-form` for the phone number. | | `countryFieldName` | `string` | No | `'billing_address.country'` | The name of the form field that stores the selected country's ISO2 code. This allows the phone input's country to be synchronized with other parts of your form, such as an address component. | ## Usage To use the `PhoneInput` component, you must wrap it in a `FormProvider` from `react-hook-form`. The following example demonstrates a basic implementation with validation. First, you need the asynchronous validation function provided by the library. ```javascript phone-validator.js icon=logos:javascript // src/libs/phone-validator.js import { getPhoneUtil } from '@blocklet/payment-react/libs/phone-validator'; export const validatePhoneNumber = async (phoneNumber) => { if (!phoneNumber) return true; try { const util = await getPhoneUtil(); const parsed = util.parseAndKeepRawInput(phoneNumber); return util.isValidNumber(parsed); } catch (err) { console.error('Phone validation error:', err); // Fallback to a simple regex if lib fails to load const pattern = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im; return pattern.test(phoneNumber) || 'Invalid phone number'; } }; ``` Now, you can use this validator in your form component. ```jsx MyPaymentForm.tsx icon=logos:react import { FormProvider, useForm } from 'react-hook-form'; import { Button, Box } from '@mui/material'; import { PhoneInput } from '@blocklet/payment-react'; import { validatePhoneNumber } from '../libs/phone-validator'; // Adjust path as needed export default function MyPaymentForm() { const methods = useForm({ mode: 'onBlur', defaultValues: { phone: '', 'billing_address.country': 'us', // Default country }, }); const onSubmit = (data) => { alert(JSON.stringify(data, null, 2)); }; return ( <FormProvider {...methods}> <form onSubmit={methods.handleSubmit(onSubmit)}> <Box display="flex" flexDirection="column" gap={2}> <PhoneInput label="Phone Number" name="phone" // Link to the country field in the form state countryFieldName="billing_address.country" // Add validation rules rules={{ validate: async (value) => { const isValid = await validatePhoneNumber(value); return isValid || 'Please enter a valid phone number.'; }, }} fullWidth /> <Button type="submit" variant="contained"> Submit </Button> </Box> </form> </FormProvider> ); } ``` ### Explanation 1. **`FormProvider`**: The entire form, including the `PhoneInput`, is wrapped in a `FormProvider` to provide the necessary form context. 2. **`name="phone"`**: This registers the input field under the name `phone` in the form data. 3. **`countryFieldName="billing_address.country"`**: This tells `PhoneInput` to both read from and write to the `billing_address.country` field in the form's state. This is how it stays synchronized. The default value for this field is set to `'us'` in `useForm`. 4. **`rules`**: We pass an asynchronous `validate` function to the `rules` prop. `react-hook-form` will await this function to resolve during validation. The `validatePhoneNumber` utility is called to perform the check. ## Integration with AddressForm The true power of `PhoneInput` is revealed when used alongside an `AddressForm`. Since both components can be linked to the same country field (`billing_address.country` by default), changing the country in the `AddressForm` will automatically update the flag and dial code in the `PhoneInput`. For a complete example of this integration, please see the documentation for [`AddressForm`](./components-ui-form-elements-address-form.md).