Gilbert Ozioma
Gilbert Ozioma

Reputation: 21

How to attach JavaScript to Filament form builder

I'm working on a Laravel project using Livewire for dynamic UI updates and Filament Form Builder to create forms. In one of my forms, I have a PhoneInput field where users can input their phone numbers.

Here's what I'm trying to achieve:

  1. As the user types their phone number in the PhoneInput field, I want to dynamically check if the inputted phone number exists in the database when it reaches 11 digits.
  2. If the inputted phone number doesn't exist in the database, I want to trigger a modal for OTP verification.
  3. The OTP verification modal will allow users to enter the OTP sent to their phone number to verify it.
  4. Once the phone number is verified, the user can submit the form.

I cannot directly attach JavaScript event listeners to Filament Form Builder fields. Therefore, I'm seeking guidance on achieving this functionality using Livewire and possibly other Laravel components.

I would greatly appreciate any suggestions or examples on how to implement this dynamic phone number verification feature using Livewire and Filament Form Builder. Thank you!

Here's the form:

// Livewire component setup
class YourLivewireComponent extends Component
{
    public $phone_number;

    public function detailForm(Form $form): Form
    {
        return $form->schema([
            ToggleButtons::make('for_sale_by')
                ->label(__('messages.t_for_sale_by'))
                ->live()
                ->grouped()
                ->options([
                    'owner' => __('messages.t_owner_for_sale'),
                    'business' => __('messages.t_business_for_sale'),
                ]),
            MarkdownEditor::make('description')
                ->disableToolbarButtons(['attachFiles'])
                ->label(__('messages.t_description'))
                ->live(onBlur: true)
                ->minLength(20)
                ->required(),
            ToggleButtons::make('condition_id')
                ->label(__('messages.t_condition'))
                ->live()
                ->options(AdCondition::all()->pluck('name', 'id'))
                ->inline(),
            Select::make('price_type_id')
                ->selectablePlaceholder(false)
                ->label(__('messages.t_price'))
                ->live()
                ->required()
                ->options(PriceType::all()->pluck('name', 'id')),
            TextInput::make('price')
                ->helperText(__('messages.t_set_fair_price'))
                ->required()
                ->numeric()
                ->minValue(1)
                ->placeholder(__('messages.t_price_your_ad'))
                ->prefix(config('app.currency_symbol'))
                ->live(onBlur: true)
                ->hidden(fn (Get $get): bool => $get('price_type_id') != 1)
                ->hiddenLabel(),
            ToggleButtons::make('display_phone')
                ->label(__('messages.t_display_phone_number'))
                ->live()
                ->required()
                ->boolean()
                ->grouped(),
            // PhoneInput::make('phone_number')
                // ->placeholder(__('messages.t_enter_phone_number'))
                // ->helperText(__('messages.t_phone_number_helper'))
                // ->required()
                // ->wire:model.debounce.500ms="phone_number"
                // ->hidden(fn (Get $get): bool => !$get('display_phone'))
                // ->hiddenLabel(),
                <PhoneInput
                id="phone_number"
                name="phone_number"
                wire:model.debounce.500ms="phone_number"
                placeholder="{{ __('messages.t_enter_phone_number') }}"
                helperText="{{ __('messages.t_phone_number_helper') }}"
                required
                @input="checkPhoneNumberExistence"
                >
                </PhoneInput>,
            TagsInput::make('tags')
                ->label(__('messages.t_tags'))
                ->helperText(__('messages.t_set_tags'))
                ->live(onBlur: true),
        ]);
    }

    public function saveNewPhoneNumber(Request $request)
    {
        $otp = $request->input('otp');
        $user = User::where('otp', $otp)->first();

        if ($user && $otp === '123456') {
            // OTP is correct, update user table and proceed with ad creation
            $user->update([
                'phone_number' => $this->phone_number,
                'phone_number_verified_at' => now()
            ]);
            $this->dispatchBrowserEvent('show-success-message', ['message' => 'Phone number verified successfully.']);
        } else {
            // OTP is incorrect, display error message
            $this->dispatchBrowserEvent('show-error-message', ['message' => 'The OTP you provided is incorrect.']);
        }
    }
}


            <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
            <script>
                document.addEventListener('livewire:load', function () {
                    window.livewire.on('show-success-message', message => {
                        Swal.fire('Success!', message, 'success');
                    });
    
                    window.livewire.on('show-error-message', message => {
                        Swal.fire('Error!', message, 'error');
                    });
                });

                document.addEventListener('livewire:load', function () {
                    window.livewire.on('show-otp-input', () => {
                        Swal.fire({
                            title: "Enter OTP",
                            input: "text",
                            inputAttributes: {
                                autocapitalize: "off"
                            },
                            showCancelButton: true,
                            confirmButtonText: "Verify",
                            allowOutsideClick: false,
                            preConfirm: async (otp) => {
                                try {
                                    return { otp: otp };
                                } catch (error) {
                                    Swal.showValidationMessage(`Error: ${error}`);
                                }
                            }
                        }).then((result) => {
                            if (result.isConfirmed) {
                                Livewire.emit('saveNewPhoneNumber', result.value.otp);
                            }
                        });
                    });
                });

    function checkPhoneNumberExistence(event) {
        const phoneNumber = event.target.value;
        if (phoneNumber.length === 11) {
            // Send an AJAX request to your backend endpoint
            axios.post('/check-phone-number', { phone_number: phoneNumber })
                .then(response => {
                    if (!response.data.exists) {
                        // Phone number doesn't exist, trigger the modal for OTP verification
                        Livewire.emit('show-otp-input');
                    }
                })
                .catch(error => {
                    console.error('Error checking phone number existence:', error);
                });
        }
    }
</script>

class YourController extends Controller
{
    public function checkPhoneNumberExistence(Request $request)
    {
        $phoneNumber = $request->input('phone_number');
        $user = User::where('phone_number', $phoneNumber)->exists();

        return response()->json(['exists' => $user]);
    }
}

Upvotes: 2

Views: 1340

Answers (0)

Related Questions