Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flux Editor doesn't allow forms to submit #750

Closed
colinmac17 opened this issue Nov 26, 2024 · 1 comment
Closed

Flux Editor doesn't allow forms to submit #750

colinmac17 opened this issue Nov 26, 2024 · 1 comment

Comments

@colinmac17
Copy link

colinmac17 commented Nov 26, 2024

Hi there! 👋

When I add the amazing new flux:editor to an existing form, the submit button doesn't do anything. I see nothing in the console or network tab. I'm not sure if I'm doing something wrong, but I did see someone share they had the same issue here in a comment here: #738.

Video Demonstration showing before/after adding in the editor
https://share.cleanshot.com/PdkfwsHH

Code

Blade file

<div class="grid grid-cols-1 lg:grid-cols-4">
    <x-app.profile-editor-sidebar :isPrimary="$isPrimary" :primarySport="$primarySport" :secondarySport="$secondarySport" />
    <div class="col-span-3">
        <flux:card>
            <form class="space-y-6" wire:submit="save">
                <div>
                    <flux:heading>
                        Contact
                        <flux:badge color="blue" inset="top bottom" size="sm">{{$isPrimary ? $primarySport : $secondarySport}}</flux:badge>
                    </flux:heading>
                    <flux:subheading>Your contact info displayed on your profile.</flux:subheading>
                </div>
                <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
                    {{--Email--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="email">Recruit's Email</flux:label>
                        <flux:input id="email" wire:model="form.email" />
                        <flux:error name="form.email" />
                    </flux:field>

                    {{--Phone--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="phone">Recruit's Phone #</flux:label>
                        <flux:input id="phone" wire:model="form.phone" mask="(999) 999-9999" />
                        <flux:error name="form.phone" />
                    </flux:field>

                    {{--Twitter/x Handle--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="twitter_x_handle">Recruit's Twitter/X Handle</flux:label>
                        <flux:input.group>
                            <flux:input.group.prefix>@</flux:input.group.prefix>
                            <flux:input id="twitter_x_handle" wire:model="form.twitter_x_handle" />
                        </flux:input.group>
                        <flux:error name="form.twitter_x_handle" />
                    </flux:field>

                    {{--Insta Handle--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="insta_handle">Recruit's Instagram Handle</flux:label>
                        <flux:input.group>
                            <flux:input.group.prefix>@</flux:input.group.prefix>
                            <flux:input id="insta_handle" wire:model="form.insta_handle" />
                        </flux:input.group>
                        <flux:error name="form.insta_handle" />
                    </flux:field>

                    {{--Coach Name--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="coach_name">Coach Name</flux:label>
                        <flux:input id="coach_name" wire:model="form.coach_name" />
                        <flux:error name="form.coach_name" />
                    </flux:field>

                    {{--Coach Email--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="coach_email">Coach Email</flux:label>
                        <flux:input id="coach_email" wire:model="form.coach_email" />
                        <flux:error name="form.coach_email" />
                    </flux:field>

                    {{--Coach Phone--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="coach_phone">Coach Phone #</flux:label>
                        <flux:input id="coach_phone" wire:model="form.coach_phone" mask="(999) 999-9999" />
                        <flux:error name="form.coach_phone" />
                    </flux:field>

                    {{--Parent 1 Name--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_1_name">Parent 1 Name</flux:label>
                        <flux:input id="parent_1_name" wire:model="form.parent_1_name" />
                        <flux:error name="form.parent_1_name" />
                    </flux:field>

                    {{--Parent 1 Email--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_1_email">Parent 1 Email</flux:label>
                        <flux:input id="parent_1_email" wire:model="form.parent_1_email" />
                        <flux:error name="form.parent_1_email" />
                    </flux:field>

                    {{--Parent 1 Phone--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_1_phone">Parent 1 Phone #</flux:label>
                        <flux:input id="parent_1_phone" wire:model="form.parent_1_phone" mask="(999) 999-9999" />
                        <flux:error name="form.parent_1_phone" />
                    </flux:field>

                    {{--Parent 2 Name--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_2_name">Parent 2 Name</flux:label>
                        <flux:input id="parent_2_name" wire:model="form.parent_2_name" />
                        <flux:error name="form.parent_2_name" />
                    </flux:field>

                    {{--Parent 2 Email--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_2_email">Parent 2 Email</flux:label>
                        <flux:input id="parent_2_email" wire:model="form.parent_2_email" />
                        <flux:error name="form.parent_2_email" />
                    </flux:field>

                    {{--Parent 2 Phone--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="parent_2_phone">Parent 2 Phone #</flux:label>
                        <flux:input id="parent_2_phone" wire:model="form.parent_2_phone" mask="(999) 999-9999" />
                        <flux:error name="form.parent_2_phone" />
                    </flux:field>

                    {{--Recruiting Coordinator Name--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="recruiting_coordinator_name">Recruiting Coordinator Name</flux:label>
                        <flux:input id="recruiting_coordinator_name" wire:model="form.recruiting_coordinator_name" />
                        <flux:error name="form.recruiting_coordinator_name" />
                    </flux:field>

                    {{--Recruiting Coordinator Email--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="recruiting_coordinator_email">Recruiting Coordinator Email</flux:label>
                        <flux:input id="recruiting_coordinator_email" wire:model="form.recruiting_coordinator_email" />
                        <flux:error name="form.recruiting_coordinator_email" />
                    </flux:field>

                    {{--Recruiting Coordinator Phone--}}
                    <flux:field class="col-span-2 lg:col-span-1">
                        <flux:label for="recruiting_coordinator_phone">Recruiting Coordinator Phone #</flux:label>
                        <flux:input id="recruiting_coordinator_phone" wire:model="form.recruiting_coordinator_phone" mask="(999) 999-9999" />
                        <flux:error name="form.recruiting_coordinator_phone" />
                    </flux:field>

                    {{--Additional Contacts--}}
                    <div class="col-span-2 space-y-2">
                        <flux:editor wire:model="form.additional_contacts" label="Additional Contacts Or References" description="List any additional contacts or references here. Include their name, email, and phone number if applicable." />
                    </div>
                </div>
                <div class="mt-4">
                    <x-common.primary-button type="submit">Save</x-common.primary-button>
                </div>
            </form>
        </flux:card>
    </div>
</div>

layout

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <link rel="preconnect" href="https://fonts.bunny.net">
    <link href="https://fonts.bunny.net/css?family=inter:400,500,600&display=swap" rel="stylesheet" />
    <link rel="icon" type="image/png" sizes="32x32"
          href="https://assets.productiverecruit.com/favicon-32.png">
    <link rel="icon" type="image/png" sizes="16x16">

    <title>{{ $title ?? "ProductiveRecruit" }}</title>

    <style>
        [x-cloak] { display: none !important; }
    </style>

    @fluxStyles
    @vite(['resources/css/app.css', 'resources/js/app.js'])

    @yield('head')
</head>
    <body class="min-h-screen bg-zinc-100 dark:bg-zinc-800">
        <flux:header container class="bg-zinc-50 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-700">
            <flux:sidebar.toggle class="lg:hidden mr-4" icon="bars-2" inset="left" />

            <a class="h-8 items-center mr-40 hidden dark:flex gap-2" href="{{route('app.dashboard')}}" wire:navigate>
                <img src="https://assets.productiverecruit.com/main-logo-light.png" alt="ProductiveRecruit" class="h-8" />
            </a>

            <a class="h-8 flex items-center mr-40 dark:hidden gap-2" href="{{route('app.dashboard')}}" wire:navigate>
                <img src="https://assets.productiverecruit.com/main-logo.png" alt="ProductiveRecruit" class="h-8" />
            </a>

            <flux:spacer />

            <flux:navbar class="-mb-px max-lg:hidden">
                <flux:navbar.item icon="home" href="{{route('app.dashboard')}}" wire:navigate.hover>Dashboard</flux:navbar.item>
                <flux:navbar.item icon="user-circle" href="{{route('app.profile.editor')}}" wire:navigate.hover :current="request()->is('app/profile*')">Profile</flux:navbar.item>
                <flux:navbar.item icon="envelope" badge="12" href="#" wire:navigate.hover>Email</flux:navbar.item>
                <flux:navbar.item icon="building-library" href="{{route('app.colleges.index')}}" wire:navigate.hover>Colleges</flux:navbar.item>
            </flux:navbar>

            <flux:spacer />

            <flux:navbar class="mr-4 max-lg:hidden">
                <flux:modal.trigger name="search" shortcut="cmd.k">
                 <flux:input as="button" kbd="⌘K" icon="magnifying-glass" placeholder="Search..." class="lg:min-w-48"/>
                </flux:modal.trigger>
                <flux:navbar.item icon="bell" icon-variant="outline" />
            </flux:navbar>

            <flux:dropdown position="top" align="start">
                <flux:profile :avatar="auth()->user()->profilePhotoUrl()" id="avatar-profile" />
                <flux:menu>
                    <flux:menu.item icon="credit-card">Subscription</flux:menu.item>
                    <flux:menu.item icon="cog-6-tooth">Settings</flux:menu.item>

                    <flux:menu.separator />
                    <form method="POST" action="{{route('logout')}}">
                        @csrf
                        <flux:menu.item type="submit" icon="arrow-right-start-on-rectangle">Logout</flux:menu.item>
                    </form>
                </flux:menu>
            </flux:dropdown>
        </flux:header>
        <flux:sidebar stashable sticky class="lg:hidden bg-zinc-50 dark:bg-zinc-900 border-r border-zinc-200 dark:border-zinc-700">
            <flux:sidebar.toggle class="lg:hidden" icon="x-mark" />

            <a class="h-10 items-center mr-4 px-2 hidden dark:flex" wire:navigate>
                <img src="https://assets.productiverecruit.com/main-logo-light.png" alt="ProductiveRecruit" class="h-8" />
            </a>

            <a class="h-10 flex items-center mr-4 px-2 dark:hidden" wire:navigate>
                <img src="https://assets.productiverecruit.com/main-logo.png" alt="ProductiveRecruit" class="h-8" />
            </a>

            <flux:navlist variant="outline">
                <flux:navlist.item icon="home" href="{{route('app.dashboard')}}" wire:navigate>Dashboard</flux:navlist.item>
                <flux:navlist.item icon="user-circle" href="{{route('app.profile.editor')}}" wire:navigate :current="request()->is('app/profile*')">Profile</flux:navlist.item>
                <flux:navlist.item icon="envelope" badge="12" href="#" wire:navigate>Email</flux:navlist.item>
                <flux:navlist.item icon="building-library" href="{{route('app.colleges.index')}}" wire:navigate>Colleges</flux:navlist.item>
            </flux:navlist>
        </flux:sidebar>

        <flux:main container>
            @yield('body')
        </flux:main>

        <flux:modal name="search" variant="bare" class="min-h-[30rem] w-full max-w-[30rem] px-6" x-on:keydown.cmd.k.document="$el.showModal()">
            <flux:command class="border-none shadow-lg">
                <flux:command.input placeholder="Search..." closable />

                <flux:command.items>
                    <flux:command.item icon="user-plus" kbd="⌘A">Assign to…</flux:command.item>
                    <flux:command.item icon="document-plus">Create new file</flux:command.item>
                    <flux:command.item icon="folder-plus" kbd="⌘⇧N">Create new project</flux:command.item>
                    <flux:command.item icon="book-open">Documentation</flux:command.item>
                    <flux:command.item icon="newspaper">Changelog</flux:command.item>
                    <flux:command.item icon="cog-6-tooth" kbd="⌘,">Settings</flux:command.item>
                </flux:command.items>
            </flux:command>
        </flux:modal>

        @persist('toast')
            <flux:toast position="top-right" class="pt-24" />
        @endpersist

        @fluxScripts
    </body>
</html>

Component

<?php

namespace App\Livewire\App;

use App\Domain\Profile\Traits\WithCreateSecondProfile;
use App\Domain\Profile\Traits\WithDeleteSecondaryProfile;
use App\Livewire\Forms\ProfileContactForm;
use App\Models\AthleteProfile;
use App\Models\User;
use Flux\Flux;
use Livewire\Component;

class ProfileEditorContact extends Component
{
    use WithCreateSecondProfile, WithDeleteSecondaryProfile;

    public User $user;
    public AthleteProfile $athleteProfile;
    public ProfileContactForm $form;
    public bool $isPrimary = true;
    public ?string $primarySport = null;
    public ?string $secondarySport = null;

    public function mount()
    {
        /**
         * @var User $user
         */
        $user = auth()->user();
        $this->user = $user;

        $profile = AthleteProfile::query()->where([
            'user_id' => $user->id,
            'is_primary' => $this->isPrimary
        ])->firstOrFail();
        $this->athleteProfile = $profile;

        $profileContact = $profile->contact;

        $this->form->setAthleteProfile($profile, $profileContact, $user);
    }

    public function save(): void
    {
        $saved = $this->form->store();

        Flux::toast(
            text: $saved ? 'Your changes have been saved.' : 'There was an error saving your changes.',
            variant: $saved ? 'success' : 'danger'
        );
    }

    public function render()
    {
        return view('livewire.app.profile-editor-contact');
    }
}

Form component

<?php

namespace App\Livewire\Forms;

use App\Models\AthleteProfile;
use App\Models\ProfileContact;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use Livewire\Attributes\Validate;
use Livewire\Form;

class ProfileContactForm extends Form
{
    public ?AthleteProfile $athleteProfile;
    public ?ProfileContact $profileContact;
    public ?User $user;

    #[Validate('nullable|string|email', message: 'Please enter a valid email')]
    public ?string $email;

    #[Validate('nullable|string', message: 'Please enter a valid phone')]
    public ?string $phone;

    #[Validate('nullable|string', message: 'Please enter a valid twitter handle')]
    public ?string $twitter_x_handle;

    #[Validate('nullable|string', message: 'Please enter a valid instagram handle')]
    public ?string $insta_handle;

    #[Validate('nullable|string', message: 'Please enter a valid coach name')]
    public ?string $coach_name;

    #[Validate('nullable|string|email', message: 'Please enter a valid coach email')]
    public ?string $coach_email;

    #[Validate('nullable|string', message: 'Please enter a valid coach phone')]
    public ?string $coach_phone;

    #[Validate('nullable|string', message: 'Please enter a valid parent 1 name')]
    public ?string $parent_1_name;

    #[Validate('nullable|string|email', message: 'Please enter a valid parent 1 email')]
    public ?string $parent_1_email;

    #[Validate('nullable|string', message: 'Please enter a valid parent 1 phone')]
    public ?string $parent_1_phone;

    #[Validate('nullable|string', message: 'Please enter a valid parent 2 name')]
    public ?string $parent_2_name;

    #[Validate('nullable|string|email', message: 'Please enter a valid parent 2 email')]
    public ?string $parent_2_email;

    #[Validate('nullable|string', message: 'Please enter a valid parent 2 phone')]
    public ?string $parent_2_phone;

    #[Validate('nullable|string', message: 'Please enter a valid recruiting coordinator name')]
    public ?string $recruiting_coordinator_name;

    #[Validate('nullable|string|email', message: 'Please enter a valid recruiting coordinator email')]
    public ?string $recruiting_coordinator_email;

    #[Validate('nullable|string', message: 'Please enter a valid recruiting coordinator phone')]
    public ?string $recruiting_coordinator_phone;

    #[Validate('nullable|string|max:2500', message: 'Please enter a valid additional contacts')]
    public ?string $additional_contacts;

    public function setAthleteProfile(AthleteProfile $athleteProfile, ProfileContact $profileContact, User $user): void
    {
        $this->athleteProfile = $athleteProfile;
        $this->user = $user;
        $this->profileContact = $profileContact;

        $this->email = $this->profileContact->email ?? "";
        $this->phone = $this->profileContact->phone ?? "";
        $this->twitter_x_handle = $this->profileContact->twitter_x_handle ?? "";
        $this->insta_handle = $this->profileContact->insta_handle ?? "";
        $this->coach_name = $this->profileContact->coach_name ?? "";
        $this->coach_email = $this->profileContact->coach_email ?? "";
        $this->coach_phone = $this->profileContact->coach_phone ?? "";
        $this->parent_1_name = $this->profileContact->parent_1_name ?? "";
        $this->parent_1_email = $this->profileContact->parent_1_email ?? "";
        $this->parent_1_phone = $this->profileContact->parent_1_phone ?? "";
        $this->parent_2_name = $this->profileContact->parent_2_name ?? "";
        $this->parent_2_email = $this->profileContact->parent_2_email ?? "";
        $this->parent_2_phone = $this->profileContact->parent_2_phone ?? "";
        $this->recruiting_coordinator_name = $this->profileContact->recruiting_coordinator_name ?? "";
        $this->recruiting_coordinator_email = $this->profileContact->recruiting_coordinator_email ?? "";
        $this->recruiting_coordinator_phone = $this->profileContact->recruiting_coordinator_phone ?? "";
        $this->additional_contacts = $this->profileContact->additional_contacts ?? "";
    }

    public function store(): bool
    {
        $data = $this->validate();

        try {

            $this->profileContact->update([
                'email' => $data['email'],
                'phone' => $data['phone'],
                'twitter_x_handle' => $data['twitter_x_handle'],
                'insta_handle' => $data['insta_handle'],
                'coach_name' => $data['coach_name'],
                'coach_email' => $data['coach_email'],
                'coach_phone' => $data['coach_phone'],
                'parent_1_name' => $data['parent_1_name'],
                'parent_1_email' => $data['parent_1_email'],
                'parent_1_phone' => $data['parent_1_phone'],
                'parent_2_name' => $data['parent_2_name'],
                'parent_2_email' => $data['parent_2_email'],
                'parent_2_phone' => $data['parent_2_phone'],
                'recruiting_coordinator_name' => $data['recruiting_coordinator_name'],
                'recruiting_coordinator_email' => $data['recruiting_coordinator_email'],
                'recruiting_coordinator_phone' => $data['recruiting_coordinator_phone'],
                'additional_contacts' => $data['additional_contacts'],
            ]);

            return true;
        } catch (\Throwable $e) {
            Log::warning('ProfileContactForm@store failed', ['error' => $e->getMessage()]);
            return false;
        }
    }
}
@calebporzio
Copy link
Contributor

This has been fixed and tagged: please upgrade to v1.0.28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants