Validating and saving based on radio button selection and authenticate
I am faced with three issues which all are related where I am struggling to add a event @click="isQuestion = true" on radios within a loop and validate on certain conditions based on which radio button is selected for example if authenticated then store the user id but if not its anonymous feedback if optional email not provided.
There are four entries in the database for ticket type see image for better explanation:
Three issues I need assistance with:
- Only show
I have a questionif user is authenticated - Show
subjectand hideemailanddata_protectionif radio buttonI have a questionis selected if something else is selected showemailanddata_protectionand hidesubject - Only validate and save the information based on the radio button selection
- If any radio button is selected besides
I have a questionvalidate and saveemailanddata_protection - If
I have a questionis selected validate and save everything besidesemailanddata_protection
- If any radio button is selected besides
PLEASE NOTE: most of the logic is already in place to hide certain fields if not I have a question radio button is selected by doing this x-show="!isQuestion" just not sure how to tie it to the radio buttons.
Any help or guidance is greatly appreciated
Create ticket Livewire component
<div x-data="{ isOpen: false, isQuestion: false, send: false }" @keydown.window.escape="isOpen = false" x-init="
@this.on('change-send', () => {
send = !send;
})
">
<div class="fixed bottom-0 right-0 top-0 flex items-center">
<div class="transform -rotate-90 origin-bottom-right">
<x-jet-button @click="isOpen = !isOpen" class="!rounded-none !rounded-t-lg !p-3">
{{ __('Feedback') }}
</x-jet-button>
</div>
</div>
<div class="fixed inset-0 overflow-hidden pointer-events-none" x-cloak>
<div class="absolute inset-0 overflow-hidden">
<div x-show="isOpen" x-description="Background overlay, show/hide based on slide-over state." x-transition:enter="ease-in-out duration-500" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="ease-in-out duration-500" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" class="absolute inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
<section class="absolute inset-y-0 right-0 pl-10 max-w-full flex" aria-labelledby="slide-over-heading">
<div x-show="isOpen" x-description="Slide-over panel, show/hide based on slide-over state." x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0" x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full" class="relative w-screen max-w-md pointer-events-auto">
<div x-show="isOpen" x-description="Close button, show/hide based on slide-over state." x-transition:enter="ease-in-out duration-500" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="ease-in-out duration-500" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" class="absolute top-0 left-0 -ml-8 pt-4 pr-2 flex sm:-ml-10 sm:pr-4">
<button type="button" @click="isOpen = !isOpen" class="rounded-md text-gray-300 hover:text-white focus:outline-none focus:ring-2 focus:ring-white">
<span class="sr-only">Close panel</span>
<!-- Heroicon name: outline/x -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="h-full flex flex-col py-6 bg-white shadow-xl overflow-y-scroll">
<div x-show="!send" class="px-4 sm:px-6">
<h2 id="slide-over-heading" class="text-lg font-medium text-gray-900">
{{ __('Do you have any feedback?') }}
</h2>
<p class="text-sm leading-5 text-gray-700">
{{__('We appreciate your feedback. Would you change something? Do you think something is good? We look forward to any kind of feedback.')}}
</p>
</div>
<div x-show="send" class="mt-6 relative flex-1 flex px-4 sm:px-6 justify-center items-center">
<div class="flex flex-col justify-center">
<div class="flex justify-center">
<!-- Heroicon name: outline/emoji-happy -->
<svg class="h-24 w-24" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<h3 class="text-lg leading-6 font-medium text-gray-900 px-3 mt-4 text-center">
{{ __('Thanks') }}
</h3>
<p class="p-3 text-center">
{{ __('Thank you for your feedback, it was saved successfully.') }}
</p>
</div>
</div>
<div x-show="!send" class="mt-6 relative flex-1 flex flex-col justify-between px-4 sm:px-6">
<div class="px-4 divide-y divide-gray-200 sm:px-6">
<fieldset class="space-y-2 my-4">
<x-jet-label for="feedback_type">
{{ __('Type of feedback') }}
</x-jet-label>
<div class="space-y-5">
@foreach ($ticket_types as $ticket_type)
<div>
<div class="relative flex items-start">
<div class="absolute flex items-center h-5">
<x-radio-button wire:model="ticket_type" @click="isQuestion = false" id="{{ $ticket_type->id }}" aria-describedby="{{ $ticket_type->id }}_description" value="{{ $ticket_type->id }}" class="h-4 w-4 transition duration-150 ease-in-out" />
</div>
<div class="pl-7 text-sm leading-5">
<x-jet-label for="{{ $ticket_type->id }}_title">
{{ $ticket_type->title }}
</x-jet-label>
<p id="{{ $ticket_type->id }}_description" class="text-gray-500">
{{ $ticket_type->description }}
</p>
</div>
</div>
</div>
@endforeach
</div>
<x-input-error for="ticket_type" />
</fieldset>
<div class="space-y-6 pt-6 pb-5">
<div class="space-y-1" x-show="isQuestion">
<x-jet-label for="subject">{{ __('Subject') }}</x-jet-label>
<x-jet-input wire:model="subject" id="subject" class="block mt-1 w-full" type="text" name="subject" aria-describedby="subject" />
<x-input-error for="description" />
</div>
<div class="space-y-1">
<x-jet-label for="description">
{{ __('Feedback') }}
</x-jet-label>
<x-textarea wire:model="description" id="description" rows="4" class="block mt-1 w-full"></x-textarea>
<x-input-error for="description" />
</div>
<div class="space-y-1" x-show="!isQuestion">
<div class="flex justify-between">
<x-jet-label for="email_optional">{{ __('E-mail address') }}</x-jet-label>
<span id="email_optional" class="font-normal text-sm leading-5 text-gray-500">
{{ __('optional') }}
</span>
</div>
<x-jet-input wire:model="email_optional" id="email_optional" class="block mt-1 w-full" type="email" name="email_optional" aria-describedby="email_optional" />
</div>
<div class="space-y-1" x-show="!isQuestion">
<label for="data_protection" class="flex items-center">
<x-jet-checkbox wire:model="data_protection" id="data_protection" name="data_protection" />
<span class="ml-2 text-sm text-gray-600">{{ __('I have read the privacy policy and accept it.') }}</span>
</label>
</div>
</div>
<div class="space-y-4 pt-4 pb-6" x-show="!isQuestion">
<div class="text-sm leading-5" x-data="{extra: false}">
<a href="#" x-on:click.prevent="extra = !extra" class="group space-x-2 inline-flex items-center text-gray-500 hover:text-gray-900 transition ease-in-out duration-150">
<svg class="h-5 w-5 text-gray-400 group-hover:text-gray-500 transition ease-in-out duration-150" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"></path>
</svg>
<span>
{{ __('Why should you provide your email address?') }}
</span>
</a>
<div x-show.transition="extra">
<p class="ml-7">
{{ __('If you include your email address, we will give you feedback on your feedback. We will never use your email address for any other purpose.') }}
</p>
</div>
</div>
</div>
</div>
</div>
<div x-show="!send" class="flex-shrink-0 px-4 py-4 space-x-4 flex justify-end">
<span class="inline-flex rounded-md shadow-sm">
<x-jet-secondary-button @click="isOpen = false">
{{ __('cancel') }}
</x-jet-secondary-button>
</span>
<span class="inline-flex rounded-md shadow-sm">
<x-jet-button wire:click="send">
{{ __('send') }}
</x-jet-button>
</span>
</div>
<div x-show="send" class="flex-shrink-0 px-4 py-4 space-x-4 flex justify-end">
<span class="inline-flex rounded-md shadow-sm">
<x-jet-secondary-button @click="isOpen = false">
{{ __('close') }}
</x-jet-secondary-button>
</span>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
Livewire backend logic
<?php
namespace App\Http\Livewire\Tickets;
use App\Models\Ticket;
use App\Rules\SpamFree;
use Livewire\Component;
class CreateTicketSlideOver extends Component
{
public $ticket_type;
public $subject;
public $description;
public $email_optional;
public $data_protection = false;
public $currentPage;
public function mount()
{
$this->currentPage = url()->current();
}
public function send()
{
$this->validate([
'ticket_type' => 'required',
'subject' => ['required', new SpamFree],
'description' => ['required', new SpamFree],
'email_optional' => ['nullable', 'email'],
'data_protection' => 'accepted',
]);
Ticket::create([
'user_id' => auth()->id(),
'ticket_type' => $this->ticket_type_id,
'slug' => $this->subject,
'subject' => $this->subject,
'description' => $this->body,
'email' => $this->email,
'url' => $this->currentPage,
]);
$this->emitSelf('change-send');
}
public function render()
{
return view('tickets.create-ticket-slide-over');
}
}
Database migration for ticket
Schema::create('tickets', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id');
$table->foreignId('ticket_type_id');
$table->string('slug')->unique();
$table->string('title');
$table->text('body');
$table->string('email')->nullable();
$table->string('url')->nullable();
$table->boolean('locked')->default(false);
$table->unsignedInteger('visits')->default(0);
$table->timestamps();
});
Please or to participate in this conversation.
