1
\$\begingroup\$

I've built this complex form or at least what I would consider a complex form and it feels really dirty. It felt dirty while I was programming it but I wanted to get it working and then go back and refactor it. The form consists of the days of the week and for each day there are three options (breakfast, lunch, dinner) and for each one of these a user can upload an image and a description. At the very end of the form is a special occasion which doesn't include a breakfast, lunch, or dinner option. Here is what the form looks like:

Form build with laravel livewire

The way I got this to is by turning what they checked so for instance Monday and Breakfast into a key which I store in the database as monday_breakfast and this is how I reference it in the code. Below I've included the code for this. Let me know your thoughts, I know there is a better way to accomplish this. Thanks!

Create.php

<?php

namespace App\Http\Livewire\Specials\Modals;

use App\Http\Livewire\Locations\Show;
use Exception;
use App\Models\Location;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Livewire\WithFileUploads;
use LivewireUI\Modal\ModalComponent;

class Create extends ModalComponent
{
    use WithFileUploads;

    public $location;

    public array $days = [];
    public array $times = [];
    public array $dow = [];
    public array $tod = [];

    public $photos = [];
    public $descriptions = [];

    public function mount(Request $request, Location $location)
    {
        $this->location = $location;
        $this->daysOfTheWeek();
        $this->timesOfTheDay();

        $this->setupSpecials();
    }

    public function setupSpecials()
    {
        $this->location->specials()->each(function ($value, $key) {
            if ($value['key'] === 'special_occasion') {
                array_push($this->dow, 'special_occasion');
            } else {
                $key = explode('_', $value['key']);

                array_push($this->dow, $key[0]);
                array_push($this->tod, $value['key']);
            }

            if ($value['image']) {
                $this->photos[$value['key']] = env('AWS_URL') . $value['image'];
            }

            $this->descriptions[$value['key']] = $value['description'];
        });
    }

    public function render()
    {
        return view('livewire.specials.modals.create');
    }

    public function chosenDay($day)
    {
        if (in_array($day, $this->dow)) {
            $key = array_search($day, $this->dow);
            array_splice($this->dow, $key);
        } else {
            array_push($this->dow, $day);
        }
    }

    public function chosenTime($time)
    {
        if (in_array($time, $this->tod)) {
            $key = array_search($time, $this->tod);
            array_splice($this->tod, $key);
        } else {
            array_push($this->tod, $time);
        }
    }

    public function timesOfTheDay()
    {
        $this->times = [
            'breakfast',
            'lunch',
            'dinner',
        ];
    }

    public function daysOfTheWeek()
    {
        $this->days = [
            'monday',
            'tuesday',
            'wednesday',
            'thursday',
            'friday',
            'saturday',
            'sunday',
            'special_occasion'
        ];
    }

    public function submit()
    {
        $arr3 = [];

        foreach ($this->descriptions as $key => $description) {
            // if the special exists, update the image and description.
            if ($special = $this->location->specials()->where('key', $key)->first()) {
                $photo = array_key_exists($key, $this->photos) ? $this->photos[$key] : null;

                if ($photo && !is_string($photo)) {
                    $special->deleteImageFromS3();
                    $path = $photo->storePubliclyAs(request()->user()->awsSpecialsDirectory(), Str::random(6), 's3');

                    $special->update([
                        'image' => $path,
                        'description' => $description,
                    ]);
                }

                $special->update([
                    'description' => $description,
                ]);

            }

            // if the special doesn't exist we're going to create one.
            if (!$this->location->specials()->where('key', $key)->count()) {
                $photo = array_key_exists($key, $this->photos) ? $this->photos[$key] : null;

                if ($photo) {
                    $path = $photo->storePubliclyAs(request()->user()->awsSpecialsDirectory(), Str::random(6), 's3');
                }

                $arr3[$key] = [
                    'key' => $key,
                    'image' => $photo ? $path : null,
                    'description' => $description,
                    'day_of_week' => $key === 'special_occasion' ? 8 : $this->getIntegerForDayOfWeek(explode('_', $key)[0]),
                    'meal_of_day' => $key === 'special_occasion' ? 0 : $this->getIntegerForMealOfDay(explode('_', $key)[1]),
                ];
            }
        }

        $this->location->specials()->createMany($arr3);

        $this->closeModalWithEvents([
            Show::getName() => ['locationUpdated', [$this->location]]
        ]);
    }

    /**
     * Returns the key for the searched value.
     * @param $dow
     * @return false|int|string
     */
    private function getIntegerForDayOfWeek($dow)
    {
        return array_search($dow, $this->days);
    }

    /**
     * Returns the key for the searched value.
     * @param $mod
     * @return false|int|string
     */
    private function getIntegerForMealOfDay($mod)
    {
        return array_search($mod, $this->times);
    }
}

create.blade.php

<div>
    <form class="space-y-6" wire:submit.prevent="submit">
        <div class="flex py-3 px-4 bg-gray-100">
            <p>Create Special</p>
        </div>
        <div class="px-4">
            @if (session()->has('success'))
                <div class="">
                    {{ session('message') }}
                </div>
            @endif
            <div class="mt-3 grid grid-cols-1 gap-3">
                @foreach($days as $key => $day)
                <div class="bg-gray-100 p-2 rounded-md">
                    <div class="flex items-center py-2">
                        <input id="{{$day}}" wire:click="chosenDay('{{$day}}')" type="checkbox" {{ in_array($day, $dow) ? 'checked' : '' }} class="h-4 w-4 text-cyan-600 focus:ring-cyan-500 border-gray-300 rounded">
                        <label for="{{$day}}" class="ml-2 block text-md font-bold text-gray-900">
                            {{ $day === 'special_occasion' ? 'Special Occasion' : ucwords($day) }}
                        </label>
                    </div>
                    @if(in_array($day, $dow))
                        @if ($day !== 'special_occasion')
                            @foreach($times as $time)
                                <div class="py-2 ml-6">
                                    <div class="flex items-center">
                                        <input id="{{$day . '_' . $time}}" wire:click="chosenTime('{{$day . '_' . $time}}')" type="checkbox" {{ in_array($day . '_' . $time, $tod) ? 'checked' : '' }} class="h-4 w-4 text-cyan-600 focus:ring-cyan-500 border-gray-300 rounded">
                                        <div class="flex justify-between items-center w-full">
                                            <label for="{{$day . '_' . $time}}" class="ml-2 block text-md font-bold text-gray-900">
                                                {{ ucwords($time) }}
                                            </label>
                                        </div>
                                    </div>
                                    @if(in_array($day . '_' . $time, $tod))
                                    <div class="flex mt-2">
                                        <label for="{{ 'image_' . $day . '_' . $time }}" class="flex-none cursor-pointer mr-3 flex items-center justify-center bg-white shadow rounded-md h-14 w-14 text-xs hover:bg-gray-50 hover:border hover:border-gray-300">
                                            @if(array_key_exists($day . '_' . $time, $photos))
                                                <img src="{{ is_string($photos[$day . '_' . $time]) ? $photos[$day . '_' . $time] : $photos[$day . '_' . $time]->temporaryUrl() }}" class="object-cover w-full h-14">
                                            @else
                                                Image
                                            @endif
                                            <input class="sr-only" id="{{ 'image_' . $day . '_' . $time }}" wire:model.defer="photos.{{ $day . '_' . $time }}" accept="image/*" type=file />
                                        </label>
                                        <div class="flex-grow">
                                            <textarea type="text" placeholder="Enter short description" wire:model.defer="descriptions.{{ $day . '_' . $time }}" class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea>
                                        </div>
                                    </div>
                                    @endif
                                </div>
                            @endforeach
                        @else
                            <div class="flex mt-2">
                                <label for="{{ 'image_' . $day }}" class="flex-none cursor-pointer mr-3 flex items-center justify-center bg-white shadow rounded-md h-14 w-14 text-xs hover:bg-gray-50 hover:border hover:border-gray-300">
                                    @if(array_key_exists($day, $photos))
                                        <img src="{{ is_string($photos[$day]) ? $photos[$day] : $photos[$day]->temporaryUrl() }}" class="object-cover w-full h-14">
                                    @else
                                        Image
                                    @endif
                                    <input class="sr-only" id="{{ 'image_' . $day }}" wire:model="photos.{{ $day }}" accept="image/*" type=file />
                                </label>
                                <div class="flex-grow">
                                    <textarea type="text" placeholder="Enter short description" wire:model="descriptions.{{ $day }}" class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea>
                                </div>
                            </div>
                        @endif
                    @endif
                </div>
                @endforeach
            </div>
        </div>

        <div class="flex justify-end py-3 px-4 bg-gray-100">
            <button wire:click="$emit('closeModal')" type="button" class="mr-2 inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-gray-600 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500">
                Cancel
            </button>
            <button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500">
                Submit
            </button>
        </div>
    </form>
</div>
```
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Consider keeping the "day of week" and "time of day" in two different columns. That would be more flexible in the future, i.e. for reports generation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.